windows 上的写时复制文件映射
Copy-on-write file mapping on windows
我有 3 个进程通过命名管道进行通信:服务器、编写器、reader。基本思想是 writer 可以在 server 上存储巨大的 (~GB) 二进制 blob,而 reader(s) 可以找回。但不是在命名管道上发送数据,而是使用内存映射。
服务器创建一个未命名的文件备份映射CreateFileMapping
PAGE_READWRITE
保护,然后将句柄复制到writer 。在 writer 完成其工作后,句柄被复制到任意数量的感兴趣的 readers.
编写器在FILE_MAP_WRITE
模式下将句柄映射到MapViewOfFile
。
reader在FILE_MAP_READ|FILE_MAP_COPY
模式下将句柄映射为MapViewOfFile
。
在 reader 上,我想要写时复制语义,因此只要只读取映射,它就会在所有 reader 实例之间共享.但是如果 reader 想要写入它(例如,就地解析或图像处理),影响应该限制在尽可能少的复制页面数量的修改过程中。
问题
当 reader 尝试写入映射时,它会因分段错误而死,就好像没有考虑 FILE_MAP_COPY
一样。
上述方法有什么问题?根据 MSDN,这应该有效...
我们在 linux 上也实现了相同的机制(mmap
和 fd 传入 AF_UNIX 辅助缓冲区)并且它按预期工作。
这里的问题是MapViewOfFile
bad designed or/and documented. this is shell (with restricted functionality) over ZwMapViewOfSection
. the dwDesiredAccess parameter of MapViewOfFile
converted to Win32Protect parameter of ZwMapViewOfSection
。
FILE_MAP_READ|FILE_MAP_COPY
组合转换为 PAGE_READONLY
页面保护,因为这样你会在写入时遇到页面错误。
你只需要使用 FILE_MAP_COPY
标志 - 它转换为 PAGE_WRITECOPY
页面保护,在这种情况下一切都会起作用。
最好的办法当然是直接使用ZwMapViewOfSection
加上PAGE_WRITECOPY
页面保护
TL:DR: RbMm 是正确的,您必须将 just FILE_MAP_COPY
传递给 MapViewOfFile
以获得写时复制行为。
当前的 Microsoft 文档不正确,它错误地指出 FILE_MAP_COPY
可以与 FILE_MAP_<ALL_ACCESS|READ|WRITE>
进行“或”运算。
查看旧版本的 MSDN it correctly says 您必须选择一种访问模式:
Type of access to the file view and, therefore, the protection of the pages mapped by the file. This parameter can be one of the following values.
- FILE_MAP_WRITE
- FILE_MAP_READ
- FILE_MAP_ALL_ACCESS
- FILE_MAP_COPY
不再相关但仍然令人惊讶,在 Windows 95/98/ME 上,写时复制行为仅适用于文件,写入 are 传播到在其他进程中的意见!
我有 3 个进程通过命名管道进行通信:服务器、编写器、reader。基本思想是 writer 可以在 server 上存储巨大的 (~GB) 二进制 blob,而 reader(s) 可以找回。但不是在命名管道上发送数据,而是使用内存映射。
服务器创建一个未命名的文件备份映射CreateFileMapping
PAGE_READWRITE
保护,然后将句柄复制到writer 。在 writer 完成其工作后,句柄被复制到任意数量的感兴趣的 readers.
编写器在FILE_MAP_WRITE
模式下将句柄映射到MapViewOfFile
。
reader在FILE_MAP_READ|FILE_MAP_COPY
模式下将句柄映射为MapViewOfFile
。
在 reader 上,我想要写时复制语义,因此只要只读取映射,它就会在所有 reader 实例之间共享.但是如果 reader 想要写入它(例如,就地解析或图像处理),影响应该限制在尽可能少的复制页面数量的修改过程中。
问题
当 reader 尝试写入映射时,它会因分段错误而死,就好像没有考虑 FILE_MAP_COPY
一样。
上述方法有什么问题?根据 MSDN,这应该有效...
我们在 linux 上也实现了相同的机制(mmap
和 fd 传入 AF_UNIX 辅助缓冲区)并且它按预期工作。
这里的问题是MapViewOfFile
bad designed or/and documented. this is shell (with restricted functionality) over ZwMapViewOfSection
. the dwDesiredAccess parameter of MapViewOfFile
converted to Win32Protect parameter of ZwMapViewOfSection
。
FILE_MAP_READ|FILE_MAP_COPY
组合转换为 PAGE_READONLY
页面保护,因为这样你会在写入时遇到页面错误。
你只需要使用 FILE_MAP_COPY
标志 - 它转换为 PAGE_WRITECOPY
页面保护,在这种情况下一切都会起作用。
最好的办法当然是直接使用ZwMapViewOfSection
加上PAGE_WRITECOPY
页面保护
TL:DR: RbMm 是正确的,您必须将 just FILE_MAP_COPY
传递给 MapViewOfFile
以获得写时复制行为。
当前的 Microsoft 文档不正确,它错误地指出 FILE_MAP_COPY
可以与 FILE_MAP_<ALL_ACCESS|READ|WRITE>
进行“或”运算。
查看旧版本的 MSDN it correctly says 您必须选择一种访问模式:
Type of access to the file view and, therefore, the protection of the pages mapped by the file. This parameter can be one of the following values.
- FILE_MAP_WRITE
- FILE_MAP_READ
- FILE_MAP_ALL_ACCESS
- FILE_MAP_COPY
不再相关但仍然令人惊讶,在 Windows 95/98/ME 上,写时复制行为仅适用于文件,写入 are 传播到在其他进程中的意见!