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

我目前尝试使用Windows CreateFileMapping机制来实现一些进程间通信。 我知道我需要先用CreateFileMapping创build一个文件映射对象,然后用MapViewOfFile创build一个指向实际数据的指针。 该示例然后通过使用CopyMemory将数据放入映射文件中。

在我的应用程序中,我有一个图像缓冲区(1 MB大),我想发送到另一个进程。 所以现在我查询一个指向图像的指针,然后将整个图像缓冲区复制到mapfile中。 但是我想知道这是否真的有必要。 是不是可以只复制指向图像缓冲区数据的共享内存中的实际指针? 我试了一下,但没有成功。

不同的进程有不同的地址空间。 如果您将一个进程中的有效指针传递给另一个进程,则可能会指向第二个进程中的随机数据。 所以你将不得不复制所有的数据。

强烈建议你使用Boost :: interprocess 。 它有很多好东西来管理这种东西,甚至包括一些特殊的Windows专用功能,以防您需要与其他使用特定Win32功能的进程进行互操作。

最重要的是使用偏移指针而不是常规指针。 偏移指针基本上是相对指针(它们存储指针所在的位置和指向的位置之间的区别)。 这意味着,即使这两个指针映射到不同的地址空间,只要映射结构相同,那么你很好。

我已经使用各种复杂的数据结构与偏移智能指针,它的工作就像一个魅力。

共享内存不意味着发送和接收数据。 它为没有违规的进程数创建了一个内存。 为此,你必须遵循一些像锁一样的机制,以便数据不会被破坏。

在过程1中:

CreateFileMapping() :如果成功,它将创建共享内存块,使用最后一个参数中提供的名称,如果它尚不存在,并返回一个句柄(您可以称之为指针)。

MapViewOfFile() :它在进程地址空间映射(包含)这个共享块并返回一个句柄(也可以说一个指针)。

MapViewOfFile()返回的这个指针,只有你可以访问那个共享块。

在过程2中:

OpenFileMapping() :如果共享内存块由CreateFileMapping()成功创建,则可以使用相同的名称(用于创建共享内存块的名称)。

UnmapViewOfFile() :它将取消映射(您可以从该进程地址空间中删除共享内存块)。 当你完成使用共享内存(即访问,修改等)调用此功能。

Closehandle() :最后将共享内存块从进程中分离出来,用参数(OpenFileMapping()或CreateFileMapping())返回句柄。

虽然这些功能看起来很简单,但是如果标志没有被正确选择,这种行为就很棘手。 如果您希望读取或写入共享内存,请在CreateFileMapping()指定PAGE_EXECUTE_READWRITE

无论您何时希望在创建成功后访问共享内存,请在MapViewOfFile()使用FILE_MAP_ALL_ACCESS

最好在OpenFileMapping()指定FALSE (不要从父进程继承句柄),因为这样可以避免混淆。

您可以获得共享内存,以使用Windows上的两个进程使用相同的地址 。 这是可以用几种技术实现的。

使用MapViewOfFileEx ,这里是MSDN的重要经验。

如果提供了建议的映射地址,则如果在指定地址处有足够的地址空间,则将文件映射到指定的地址(向下舍入到最接近的64K边界)。 如果地址空间不足,则该功能失败。

通常,建议的地址用于指定文件应映射到多个进程中的相同地址。 这要求在所有涉及的进程中都可以使用地址空间的区域。 在用于映射的区域中不能发生其他内存分配,包括使用VirtualAlloc或VirtualAllocEx函数来保留内存。

如果lpBaseAddress参数指定了一个基本偏移量,则如果指定的内存区域尚未被调用进程使用,则该函数成功。 系统不能确保在其他32位进程中的内存映射文件使用相同的内存区域。

另一个相关技术是使用一个标记为Read + Write + Shared的部分的DLL。 在这种情况下,操作系统将为您和任何其他加载DLL的进程调用MapViewOfFileEx。

你可能必须标记你的DLL到一个固定的加载地址,而不是可重定位等。

你可以使用指针的编组。

如果可能,最好将图像数据直接加载/生成到共享内存区域。 这消除了内存复制,并将其直接放在需要的地方。 准备就绪后,您可以发信号通知另一个进程,并将数据从数据开始处的共享内存中提供给它。