我目前尝试使用Windows CreateFileMapping机制实现一些进程间通信。我知道我需要首先使用CreateFileMapping创建文件映射对象,然后使用MapViewOfFile创建指向实际数据的指针。然后,该示例使用CopyMemory将数据放入mapfile。
在我的应用程序中,我有一个图像缓冲区(1 MB大),我想发送给另一个进程。所以现在我查询指向图像的指针,然后将整个图像缓冲区复制到mapfile中。但我想知道这是否真的有必要。是不是可以只在共享内存中复制指向图像缓冲区数据的实际指针?我尝试了一下但没有成功。
答案 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)
如果可能,最好将图像数据直接加载/生成到共享内存区域。这消除了内存副本并将其直接放在需要的位置。当它准备就绪时,您可以发信号通知另一个进程,将其偏移到共享内存中,数据开始。