Memory Sharing (Interprocess, Local)

Hi all.

I'm fairly new to C++, and I'm building a DLL plugin for a software authoring application I use.

I need to communicate between separate processes, so I've been looking into Memory Mapped Files and Mutexes, which I'm fairly new to, but I have a question.

The application provides my DLL with a pointer to a surface which contains the screen data. I want to share this data. I know I could create a Shared Memory block, copy the surface into that, toggle my Mutex and let Process 2 copy the Surface back out of the shared block and into its own memory. But that sounds a bit wasteful to me.

Can I just give Windows a pointer to my surface in process 1's memory, tell it the length, give it a name and say 'share that, please'?

That would avoid me having to copy the surface into shared memory and then copy it out. If that is possible, then presumably I could just let each process point to the same surface in memory, using the Mutexes to toggle permissions?

Or have I gone completely mad?
Hi Jose,

I'm trying to avoid needing to use CopyMemory() or equivalents if possible. I have a very large buffer, you see, and that's the data I need to share.

I would normally just store the buffer in the region of shared memory, but unfortunately the buffer is declared by the parent program, whereas I'm programming a DLL which is attached to it. My context is a bit like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void WINAPI DLLExport ParentCallsMe( LPVOID lpBuffer, int BufferSize )
{

	// This buffer is huge, it contains the surface of the parent window as a bitmap.
	// All my code has to happen in this function here.
	// Because the Buffer already exists, I'm forced to either copy it or find a way to
	//  make Windows map the buffer itself, like it would if I specified a file handle.

	HANDLE hMap;	// My handle to a new shared region

	hMap = CreateFileMapping(
		INVALID_HANDLE_VALUE,		// <- I wish I could just put lpBuffer here, so CreateFileMapping would map the buffer!
		NULL,
		PAGE_READWRITE,
		0,
		256,
		TEXT("Local\\HelloWorld")
		);
	
	if (hMap == NULL)
	{
		MessageBox( NULL, "It didn't work.", "Epic fail", MB_OK );
		return 1;
	}

	/* ...the rest goes here... */
}


Is there any way I can somehow do a sort of CreateFileMapping( (HANDLE) lpBuffer, ... ) thing, to force Windows into mapping my existing buffer, rather than giving me a new bank of memory?

I'll copy the memory if I have to, but it'll get very expensive, as this has to be able to run at 60fps.
You'll have to copy the memory. I see no other way as I don't think it is possible to provide the buffer pointer for a file mapping.
I wonder if it would be possible to do this in a back to front kind of way. In other words, if I can't make Windows share the space pointed to by lpBuffer, perhaps I could make my own space, copy the contents pointed to by lpBuffer there just once, then change lpBuffer so it now points to my new shared region instead of the private region?
If you have access to &lpBuffer, you can change it to point to the new location, effectively re-writing the pointer. BUT, how will you synchronize reads with writes?
Thanks, you've answered my question! :)

Regarding reads and writes with Shared Memory, what kind of access issues might I get? I would imagine that on a single-core machine, it should be impossible for two processes to read or write to the same address, but on a multi-core, what happens if the two try reading or writing the same area at the same time?
Chrisdines wrote:
I would imagine that on a single-core machine, it should be impossible for two processes to read or write to the same address


Strictly speaking, it is true that on single core PC's you cannot have a thread reading and another thread writing at the same exact time, but you must remember that Windows is a preemptive operating system. This means that the OS can and will in fact freeze any thread at any given point without the thread ever knowing this, and then resume some other thread, probably in some other process.

So the above means that your writing thread could be stopped in the middle of writing and then the reading thread could be scheduled to run, finally reading incomplete data because of lack of synchronization.

Chrisdines wrote:
but on a multi-core, what happens if the two try reading or writing the same area at the same time?


This is pretty much the same disastrous outcome as the previous one, but in a more obvious way.

In both cases, the end result is said to be undefined, meaning all bets are off. Anything can happen. It may work perfectly for 2 days straight and then miserably fail, or fail from attempt 1.
Ah, thank you for a very comprehensive reply! :)

So simultaneous read/write is bad, but can both read the same portion of memory at the same time? Especially on multi-core PCs, doesn't it create some kind of bottleneck if both cores want to read exactly the same byte of memory at exactly the same time? Or is the issue only reading *and writing* simultaneously?

I really appreciate your help.

Thanks
Last edited on
You can have concurrent reads as long as you don't have a write operation too. So read all you want, just don't write.

The way to allow multiple reads is to implement logic for a "shared lock". The term I am borrowing from SQL Server. SQL Server allows concurrent reads but locks out any writes, and any write operation blocks all reads and other writes.

I have never written a shared lock, so my first attempt at it would be a semaphore. Reads are allowed as long as there is a positive count in the semaphore, and a write operation would consume the entire semaphore and will write only when it is the owner of all "slots". For example, I'd create a semaphore with a maximum count of 20. This means 20 concurrent reads are allowed. If a thread wanted to write, it would do:

1
2
3
4
5
6
7
8
9
10
11
12
13
//Save the count of successful waits
DWORD dwWaits = 0;
for (; dwWaits < 20; ++dwWaits)
{
    WaitForSingleObject(mySemaphore, INFINITE);
}
//Semaphore consumed.  Write.
...
//Release the entire semaphore.
//Production-grade code needs to account for errors and release the semaphore
//by the proper amount in the case of errors.  Best to code a class that does cleanup
//during destruction.
ReleaseSemaphore(mySemaphore, dwWaits);
Last edited on
Thanks for your replies, I really appreciate it.

As I plan to have two processes only sharing the data, I was thinking of using a Mutex to handle them both, so one process is always stopped when the other is handling the data.
Topic archived. No new replies allowed.