Windows上的写时复制文件映射

问题描述 投票:1回答:2

我有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辅助缓冲区中传递)并且它按预期工作。

c++ winapi shared-memory
2个回答
5
投票

这里的问题,MapViewOfFile设计错误或/和记录。这是ZwMapViewOfSection上的shell(功能受限)。 MapViewOfFile的dwDesiredAccess参数转换为ZwMapViewOfSection的Win32Protect参数。

FILE_MAP_READ|FILE_MAP_COPY组合转换为PAGE_READONLY页面保护,因为这样你就可以在写入时获得页面错误。

你需要使用FILE_MAP_COPY only flag - 它转换为PAGE_WRITECOPY页面保护,在这种情况下所有都将工作。

最好的解决方案当然直接使用ZwMapViewOfSectionPAGE_WRITECOPY页面保护


1
投票

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上,写时复制行为仅适用于文件,写入会传播到其他进程中的视图!

© www.soinside.com 2019 - 2024. All rights reserved.