CreateFileMapping 程序之间同步?
我计划使用内存映射打开一个文件。
该文件已被另一个进程以相同的方式打开,即它打开了自己的内存映射视图,并且时不时地编辑该文件。
我希望自己编辑同一个文件,并尽可能有效地与其他进程共享对它的访问权限,而不希望每个进程覆盖另一个进程所做的更改而发生冲突。
首先,我可以直接打开文件:
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。
文件系统或文件映射系统似乎以某种方式理解这一点。为什么?
// 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);
I plan to open a file using memory mapping.
The file is already open by another process in the same way i.e. it has its own memory map view open and from time to time edits the file.
I wish to edit the same file myself and share access to it with the other process as effectively as possible without hopefully conflicting by each process over-writing changes made by the other.
I can first of all open the file directly:
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);
Editing the file binary directly, however, is ineffective in that the other process's memory mapping objects are liable to over-write my changes.
If I open my own file mapping and my own view, as below, the other process seems to become automatically updated with my edits in such a way that it does not overwrite my edits.
What synchronicity is going on here?
It is not that I have opened my own mapped view to the other processes' file mapping. I have created an entirely new FileMapping on the same file.
The filesystem or FileMapping system seems to somehow understand this. Why?
// 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);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
任何拥有该文件可写视图的人都可以随时写入该文件。如果您希望两个编辑器都能够可靠地写出更改,则必须在更改重叠的情况下执行自己的冲突解决方案。
这似乎不是一个非常容易解决的问题 - 也许您需要一个简单的文档版本控制系统来允许以受控方式合并多个编辑。
Anybody with a writable view of the file can write to it at any time. If you want both editors to be able to reliably write out changes, you will have to perform your own conflict resolution where changes overlap.
This does not seem like a very simple problem to solve - perhaps you need a simple document versioning system to allow multiple edits to be merged in a controlled way.
一种想法是,您可以在获取命名互斥体(可以通过调用
CreateMutex()
,名称参数为非 NULL)。例如(省略错误处理):
根据您访问它的方式,您可能还需要在读取时获取锁。这当然会限制你的并发性。
顺便说一下,其他一些杂项。评论:
如果您在
FlushViewOfFile
调用中比“从视图开始到结束”更具体,这也可能会表现得更好。例如,如果您在偏移量i
处写入n
个字节,您可能会想说FlushViewOfFile(pView + i, n);
。操作系统有可能可以检查哪些页面是脏的,并且只执行最少量的写入(MSDN 似乎表明会发生这种情况),但也许在较小的范围内会做得更好;这只是我的猜测。映射文件时,如果 I/O 失败,您可能会在执行指针取消引用时遇到
EXCEPTION_IN_PAGE_ERROR
异常。您可以使用 SEH 捕获这些内容(如 此 MSDN 页面)。One idea is that you could do the writes (and the
FlushViewOfFile()
call) while acquiring a named mutex (which you can create by callingCreateMutex()
with a name parameter of non-NULL).For example (error handling omitted):
Depending on the way that you access this, you may need to also acquire the lock while reading. This will of course limit your concurrency.
By the way, some other misc. commentary:
This might also perform better if you're more specific than "from the start of the view until the end" at the
FlushViewOfFile
call. For example if you writen
bytes at offseti
, you might want to sayFlushViewOfFile(pView + i, n);
. It's possible that the OS can check what pages are dirty and only do a minimal amount of writes (MSDN seems to suggest this happens), but perhaps it will do better with a smaller range; that's just a guess on my part.When mapping files you can get
EXCEPTION_IN_PAGE_ERROR
exceptions doing pointer dereferences if the I/O fails. You can catch those with SEH (as in this MSDN page).