0

我计划使用内存映射打开一个文件。

该文件已经被另一个进程以相同的方式打开,即它有自己的内存映射视图打开并且不时编辑该文件。

我希望自己编辑同一个文件,并尽可能有效地与另一个进程共享对它的访问,而不希望每个进程覆盖另一个进程所做的更改而发生冲突。

我可以首先直接打开文件:

IntPtr f_ptr = CreateFile(
 path,
 GENERIC_READ | GENERIC_WRITE,
 FILE_SHARE_READ | FILE_SHARE_WRITE,
 IntPtr.Zero,
 OPEN_ALWAYS,
 FILE_FLAG_RANDOM_ACCESS,
 IntPtr.Zero);

但是,直接编辑文件二进制文件是无效的,因为其他进程的内存映射对象可能会覆盖我的更改。

如果我打开我自己的文件映射和我自己的视图,如下所示,另一个进程似乎会随着我的编辑自动更新,不会覆盖我的编辑。

这里发生了什么同步性?

并不是我打开了我自己的映射视图到其他进程的文件映射。我在同一个文件上创建了一个全新的 FileMapping。

文件系统或 FileMapping 系统似乎以某种方式理解这一点。为什么?

// file map pointer
IntPtr m_ptr = CreateFileMapping(f_ptr, IntPtr.Zero, PAGE_READWRITE, 0, 0, "MyMapping");

// map view pointer
IntPtr view_ptr = MapViewOfFileEx(m_ptr, FILE_MAP_WRITE, 0, 0, 0, IntPtr.Zero);

// EDIT FILE CONTENTS

FlushViewOfFile(view_ptr, 0);
UnmapViewOfFile(view_ptr);

CloseHandle(m_ptr);
4

2 回答 2

0

一个想法是,您可以FlushViewOfFile()在获取命名互斥体(您可以通过CreateMutex()使用非 NULL 的名称参数调用来创建)的同时进行写入(和调用)。

例如(省略错误处理):

HANDLE hMutex, hMap;
PVOID pView;

// In reality, it might be good to dynamically generate the name based on
// the file being mapped (eg. its volume and file ID, something like this..)
hMutex = CreateMutex(NULL, FALSE, TEXT("Local\\LockForThisFile"));

hMap = CreateFileMapping( /* ... */ );
pView = MapViewOfFile( /* ... */ );

// Some time later, when you need to do the writes...
//
WaitForSingleObject(hMutex, INFINITE);
PerformWrites(pView);
FlushViewOfFile(pView, 0);
ReleaseMutex(hMutex);

根据您访问它的方式,您可能还需要在读取时获取锁。这当然会限制您的并发性。

顺便说一句,其他一些杂项。评论:

  • 如果您在FlushViewOfFile通话中比“从视图开始到结束”更具体,这也可能会表现得更好。例如,如果您n在 offset 处写入字节i,您可能想说FlushViewOfFile(pView + i, n);. 操作系统可能会检查哪些页面是脏的并且只执行最少量的写入(MSDN 似乎暗示会发生这种情况),但也许它会在较小的范围内做得更好;这只是我的猜测。

  • 映射文件时,EXCEPTION_IN_PAGE_ERROR如果 I/O 失败,您可能会在指针取消引用时遇到异常。您可以使用 SEH 捕获那些(如在此 MSDN 页面中)。

于 2010-11-29T17:21:39.717 回答
0

任何对文件有可写视图的人都可以随时对其进行写入。如果您希望两个编辑器都能可靠地写出更改,则必须在更改重叠的地方执行自己的冲突解决方案。

这似乎不是一个很容易解决的问题——也许您需要一个简单的文档版本控制系统来允许以受控方式合并多个编辑。

于 2010-11-29T17:18:59.747 回答