【发布时间】:2015-10-15 15:07:51
【问题描述】:
我有两个线程和一个大型数据集。线程 R 不断地从数据集中读取数据并向用户展示数据视图。线程 W 不断接收远程数据,对其执行一些工作并将其发布到数据集。
线程 R 需要控制它接收数据集一致视图的粒度。一种解决方案是双缓冲; W 写入一个副本,而 R 读取另一个副本,当 R 准备好进行更新时,要么 W 的副本被原子地复制到 R(禁止,因为数据集很大且大部分未更改),要么它们原子地交换副本,W 带来 R 的旧通过重新应用自上次交换以来的增量更改来复制最新(烦人的跟踪这些,并且烦人的是所有增量都必须处理两次)。
我想做的是:
- 两个线程独立保留虚拟只读内存范围,并且两个范围都映射到相同的物理页集
- 线程 W 安装一个异常处理程序,将写入捕获到只读页面,抓取一个新的物理块,将其映射为可读写,然后让写入重新尝试
- 当 R 想要更新时,原子地(在 R 看来,W 已替换的任何物理页面都被释放(或返回到池中),然后这些虚拟内存地址得到 W 的新物理页面的支持,然后 W 标记其整个范围再次只读)。
这避免了额外的内存副本、跟踪和重新应用增量等的需要。
但是,AFAICT 虽然 Windows 确实允许创建共享内存区域(甚至是自动写入时复制内存区域),但它似乎已经竭尽全力,无法以任何方式显式映射物理页面W 可以使用它来向 R 发布新视图。
我有什么遗漏吗? - 是否有可能实现这样的事情,一个纯粹通过改变页面映射来实现的发布步骤,而不需要内存副本?
【问题讨论】:
-
阅读我能找到的所有文档,所有对 COW 的引用都在写作的上下文中,通过 COW 映射为自己创建一个私有副本。我在内部如何工作的心理模型是通过我的问题中的异常机制之类的,我一直假设如果您要求对一系列地址进行 rw 保护,那么无论存在哪些其他映射,您都会真正得到,并且在那个世界中,由于作者的写入没有被困住,因此无法实现 reader-snapshot-via-COW 行为;我的假设错了吗?
-
结合使用 AWE 和 VirtualProtect() 或许可以做到这一点。如果做不到这一点,则可能来自设备驱动程序。但是,写时复制不会涉及至少与原子交换和正确方法一样多的内存复制吗?无论哪种方式,写入的每个块都会被复制一次。
-
不,AWE 不起作用:“物理页面不能同时映射到多个虚拟地址。”
标签: windows database-design shared-memory virtual-memory