使用VirtualProtect将页面标记为写时复制(Windows上的穷人分叉)

时间:2011-02-27 16:48:27

标签: c# c++ windows fork

我使用VirtualAlloc(Ex)来分配和提交大量页面。

稍后在执行中我希望“分叉”该内存,启动一个可以在其当前状态下读取它的新进程,而父进程将其视为写时复制内存。

可以使用VirtualAlloc(Ex)和VirtualProtect(Ex)完成吗?

由于fork(),这在posix系统上是微不足道的。我可以在Windows上有效地模拟这部分fork吗?

谢谢, -Dan

2 个答案:

答案 0 :(得分:4)

我不相信这些中的任何一个都能完全回答原始海报提出的问题。也许我可以尝试下面的例子。假设一个在“bufferA”中有一些数据,一个将它复制到“bufferB”,然后修改两个缓冲区。现在检查两个缓冲区,并决定将“bufferA”或“bufferB”复制到“bufferC”并对“bufferC”进行更多修改,等等。

假设缓冲区很大且修改很小,问题是在主机上使用MMU的写时复制功能是否优化,以及是否有API允许这样做

使用内存映射文件并不是很有效,因为一旦使用PAGE_WRITECOPY,似乎没有办法说“现在复制包含更改的虚拟页面”。例如,如果“bufferA”和“bufferB”都是同一文件的映射,并且在映射时其中一个标记为“WRITECOPY”,则似乎无法将这些修改映射到“bufferC”。当然可以只复制这些位,但问题是是否存在潜在的优化。

有一个名为VirtualCopy()的函数,但它似乎是特定于Windows CE的,并且与物理地址一起使用。这里的问题是是否有类似“VirtualCopy”的东西,但是以虚拟地址为源。

请注意,虽然“fork()”(在拥有它的系统上)执行此操作,但是“fork”是整个过程,而不仅仅是缓冲区。这里有一个关于“copy-on-write memcpy”的相关讨论(Can I do a copy-on-write memcpy in Linux?)。

所以正在寻找的API看起来像这样:      void * VirualCopyVirtualAddressSpace(void * src,size_t length);

到目前为止,我在任何系统上都没有看到API,它允许在进程内或现有进程之间复制缓冲区。虽然我不是专家,但我认为通过写时复制机制复制一个正确对齐的虚拟内存段可能相当简单,至少在一个地址空间内。

答案 1 :(得分:1)

如果您使用PAGE_WRITECOPY使用内存映射(CreateFileMapping / MapViewOfFile),我认为您可以这样做。

如果您为第二个进程将FILE_MAP_ALL_ACCESS更改为PAGE_WRITECOPY,则此example in MSDN可以作为起点。

如果您想要一致的时间点复制行为,您可能需要在第一个进程中使用PAGE_WRITECOPY对映射区域进行VirtualProtect(),因此第二个进程看不到任何更改。