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

时间:2009-03-30 15:20:02

标签: c++ windows shared-memory

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

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

6 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:8)

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

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

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

答案 2 :(得分:3)

共享内存并不意味着发送和接收数据。它是为多个进程创建的内存,没有违规。为此,您必须遵循一些机制,如锁定,以便数据不会损坏。

在流程1中:

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

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

只有MapViewOfFile()返回此指针,才能访问该共享块。

在过程2中:

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

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

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

虽然这些函数看起来很简单,但如果未正确选择标记,则行为很棘手。 如果您希望读取或写入共享内存,请在PAGE_EXECUTE_READWRITE中指定CreateFileMapping()

每当您希望在成功创建共享内存后访问共享内存时,请使用FILE_MAP_ALL_ACCESS中的MapViewOfFile()

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

答案 3 :(得分:2)

CAN 获取共享内存,以便在Windows的2个进程中使用相同地址。这可以通过几种技术实现。

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

  

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

     

通常,建议的地址是   用于指定文件应该是   映射到多个相同的地址   流程。这需要该地区   地址空间全部可用   涉及的过程。没有其他记忆   分配可以在   用于映射的区域,   包括使用VirtualAlloc   或VirtualAllocEx函数来保留   存储器中。

     

如果是lpBaseAddress参数   指定基本偏移量,即函数   如果指定的内存成功   区域尚未被使用   呼叫过程。系统没有   确保相同的内存区域   可用于内存映射文件   在其他32位进程中。

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

您可能必须将DLL标记为FIXED加载地址,而不是重定位等。自然。

答案 4 :(得分:0)

您可以使用指针编组。

答案 5 :(得分:0)

如果可能,最好将图像数据直接加载/生成到共享内存区域。这消除了内存副本并将其直接放在需要的位置。当它准备就绪时,您可以发信号通知另一个进程,将其偏移到共享内存中,数据开始。