简体   繁体   English

在Windows下使用共享内存。 如何传递不同的数据

[英]Using shared memory under Windows. How to pass different data

I currently try to implement some interprocess communication using the Windows CreateFileMapping mechanism. 我目前尝试使用Windows CreateFileMapping机制实现一些进程间通信。 I know that I need to create a file mapping object with CreateFileMapping first and then create a pointer to the actual data with MapViewOfFile. 我知道我需要首先使用CreateFileMapping创建文件映射对象,然后使用MapViewOfFile创建指向实际数据的指针。 The example then puts data into the mapfile by using CopyMemory. 然后,该示例使用CopyMemory将数据放入mapfile。

In my application I have an image buffer (1 MB large) which I want to send to another process. 在我的应用程序中,我有一个图像缓冲区(1 MB大),我想发送到另一个进程。 So now I inquire a pointer to the image and then copy the whole image buffer into the mapfile. 所以现在我查询指向图像的指针,然后将整个图像缓冲区复制到mapfile中。 But I wonder if this is really necessary. 但我想知道这是否真的有必要。 Isn't it possible to just copy an actual pointer in the shared memory which points to the image buffer data? 是不是可以只在共享内存中复制指向图像缓冲区数据的实际指针? I tried a bit but didn't succeed. 我尝试了一下但没有成功。

Different processes have different address spaces. 不同的进程有不同的地址空间。 If you pass a valid pointer in one process to another process, it will probably point to random data in the second process. 如果将一个进程中的有效指针传递给另一个进程,它可能会指向第二个进程中的随机数据。 So you will have to copy all the data. 所以你必须复制所有数据。

I strongly recommend you use Boost::interprocess . 强烈建议你使用Boost :: interprocess It has lots of goodies to manage this kind of stuff & even includes some special Windows-only functions in case you need to interoperate w/ other processes that use particular Win32 features. 它有很多好处来管理这种东西,甚至还包括一些特殊的Windows功能,以防你需要与使用特定Win32功能的其他进程进行互操作。

The most important thing is to use offset pointers rather than regular pointers. 最重要的是使用偏移指针而不是常规指针。 Offset pointers are basically relative pointers (they store the difference between where the pointer is and where the thing pointed to is). 偏移指针基本上是相对指针(它们存储指针所在位置和指向的位置之间的差异)。 This means that even if the two pointers are mapped to different address spaces, as long as the mappings are identical in structure then you are fine. 这意味着即使两个指针映射到不同的地址空间,只要映射结构相同,那么你就可以了。

I've used all kinds of complicated data structures with offset smart pointers and it worked like a charm. 我已经使用了各种复杂的数据结构和偏移智能指针,它就像一个魅力。

Shared Memory doesn't mean sending and receiving of Data. 共享内存并不意味着发送和接收数据。 Its a memory created for number of processes without violation. 它是为多个进程创建的内存,没有违规。 For that you have to follow some mechanisms like locks so that the data will not corrupt. 为此,您必须遵循一些机制,如锁定,以便数据不会损坏。

In process 1 : 在过程1中:

CreateFileMapping() : It will create the Shared Memory Block, with the name provided in last parameter, if it is not already present and returns back a handle (you may call it a pointer), if successful. CreateFileMapping() :它将创建共享内存块,如果它不存在则使用在最后一个参数中提供的名称并返回一个句柄(您可以将其称为指针),如果成功的话。

MapViewOfFile() : It maps (includes) this shared block in the process address space and returns a handle (again u can say a pointer). MapViewOfFile() :它在进程地址空间中映射(包括)此共享块并返回一个句柄(再次,你可以说一个指针)。

With this pointer returned by MapViewOfFile() only you can access that shared block. 使用MapViewOfFile()返回的此指针,您只能访问该共享块。

In process 2 : 在过程2中:

OpenFileMapping() : If the shared memory block is successfully created by CreateFileMapping() , you can use it with the same name (name used to create the shared memory block). OpenFileMapping() :如果CreateFileMapping()成功创建了共享内存块,则可以使用它具有相同的名称(用于创建共享内存块的名称)。

UnmapViewOfFile() : It will unmap (you can remove the shared memory block from that process address space). UnmapViewOfFile() :它将取消映射(您可以从该进程地址空间中删除共享内存块)。 When you are done using the shared memory (ie access, modification etc) call this function . 当您完成使用共享内存(即访问,修改等)时,请调用此函数。

Closehandle() : finally to detach the shared memory block from process , call this with argument,handle returned by OpenFileMapping() or CreateFileMapping(). Closehandle() :最后从进程中分离共享内存块,使用参数调用此函数,使用OpenFileMapping()或CreateFileMapping()返回的句柄。

Though these functions look simple, the behaviour is tricky if the flags are not selected properly. 虽然这些函数看起来很简单,但如果未正确选择标志,则行为很棘手。 If you wish to read or write shared memory, specify PAGE_EXECUTE_READWRITE in CreateFileMapping() . 如果要读取或写入共享内存,请在CreateFileMapping()指定PAGE_EXECUTE_READWRITE

Whenever you wish to access shared memory after creating it successfully, use FILE_MAP_ALL_ACCESS in MapViewOfFile() . 每当您希望在成功创建共享内存后访问它,请在MapViewOfFile()使用FILE_MAP_ALL_ACCESS

It is better to specify FALSE (do not inherit handle from parent process) in OpenFileMapping() as it will avoid confusion. 最好在OpenFileMapping()指定FALSE (不要从父进程继承句柄),因为它可以避免混淆。

You CAN get shared memory to use the same address over 2 processes for Windows. 可以得到共享内存超过2个进程的Windows使用相同的地址 It's achieveable with several techniques. 它可以通过几种技术实现。

Using MapViewOfFileEx , here's the significant experpt from MSDN. 使用MapViewOfFileEx ,这是MSDN的重要经验。

If a suggested mapping address is supplied, the file is mapped at the specified address (rounded down to the nearest 64K-boundary) if there is enough address space at the specified address. 如果提供了建议的映射地址,则如果指定地址处有足够的地址空间,则将文件映射到指定的地址(向下舍入到最接近的64K边界)。 If there is not enough address space, the function fails. 如果地址空间不足,则该功能失败。

Typically, the suggested address is used to specify that a file should be mapped at the same address in multiple processes. 通常,建议的地址用于指定文件应映射到多个进程中的同一地址。 This requires the region of address space to be available in all involved processes. 这要求地址空间区域在所有相关进程中可用。 No other memory allocation can take place in the region that is used for mapping, including the use of the VirtualAlloc or VirtualAllocEx function to reserve memory. 在用于映射的区域中不会发生其他内存分配,包括使用VirtualAlloc或VirtualAllocEx函数来保留内存。

If the lpBaseAddress parameter specifies a base offset, the function succeeds if the specified memory region is not already in use by the calling process. 如果lpBaseAddress参数指定基本偏移量,则如果调用进程尚未使用指定的内存区域,则该函数会成功。 The system does not ensure that the same memory region is available for the memory mapped file in other 32-bit processes. 系统无法确保在其他32位进程中可用于内存映射文件的相同内存区域。

Another related technique is to use a DLL with a section marked Read + Write + Shared. 另一种相关技术是使用具有标记为Read + Write + Shared的部分的DLL。 In this case, the OS will pretty much do the MapViewOfFileEx call for you and for any other process which loads the DLL. 在这种情况下,操作系统将为您和任何其他加载DLL的进程执行MapViewOfFileEx调用。

You may have to mark your DLL to a FIXED load address, not relocateable etc.. naturally. 您可能必须将DLL标记为FIXED加载地址,而不是可重定位等。自然。

您可以使用指针编组。

If it's possible, it would be best to have the image data loaded/generated directly into the shared memory area. 如果可能,最好将图像数据直接加载/生成到共享内存区域。 This eliminates the memory copy and puts it directly where it needs to be. 这消除了内存副本并将其直接放在需要的位置。 When it's ready you can signal the other process, giving it the offset into your shared memory where the data begins. 当它准备就绪时,您可以发信号通知另一个进程,将其偏移到共享内存中,数据开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM