我有3个进程通过命名管道进行通信:服务器,编写器,阅读器。基本思想是编写器可以在服务器上存储大量(~GB)二进制blob,并且读取器可以检索它。但是,不是在命名管道上发送数据,而是使用内存映射。
服务器使用带有CreateFileMapping
保护的PAGE_READWRITE
创建一个未命名的文件支持映射,然后将句柄复制到writer中。在作者完成其工作之后,句柄被复制到任何数量的感兴趣的读者中。
作者用MapViewOfFile
模式中的FILE_MAP_WRITE
映射句柄。
读者在MapViewOfFile
模式下使用FILE_MAP_READ|FILE_MAP_COPY
映射句柄。
在读者我想要写时复制语义,因此只要读取映射,它就会在所有读者实例之间共享。但是,如果读者想要写入(例如,就地解析或图像处理),则影响应该限于具有最少数量的复制页面的修改过程。
问题
当读者试图写入映射时,它会因为分段错误而死亡,就像没有考虑FILE_MAP_COPY
一样。上述方法有什么问题?根据MSDN,这应该工作......
我们在linux上也实现了相同的机制(mmap
和fd在AF_UNIX辅助缓冲区中传递)并且它按预期工作。
这里的问题,MapViewOfFile
设计错误或/和记录。这是ZwMapViewOfSection
上的shell(功能受限)。 MapViewOfFile
的dwDesiredAccess参数转换为ZwMapViewOfSection
的Win32Protect参数。
将FILE_MAP_READ|FILE_MAP_COPY
组合转换为PAGE_READONLY
页面保护,因为这样你就可以在写入时获得页面错误。
你需要使用FILE_MAP_COPY
only flag - 它转换为PAGE_WRITECOPY
页面保护,在这种情况下所有都将工作。
最好的解决方案当然直接使用ZwMapViewOfSection
与PAGE_WRITECOPY
页面保护
TL:DR:RbMm是正确的,你必须将FILE_MAP_COPY
传递给MapViewOfFile
才能获得写时复制行为。
当前的Microsoft文档不正确,它错误地指出FILE_MAP_COPY
可以与FILE_MAP_<ALL_ACCESS|READ|WRITE>
进行OR运算。
查看旧版本的MSDN it correctly says,您必须选择以下访问模式之一:
对文件视图的访问类型,以及对文件映射的页面的保护。此参数可以是以下值之一。
- FILE_MAP_WRITE
- FILE_MAP_READ
- FILE_MAP_ALL_ACCESS
- FILE_MAP_COPY
不再相关但仍然令人惊讶,在Windows 95/98 / ME上,写时复制行为仅适用于文件,写入会传播到其他进程中的视图!