CreateFileMapping synchronous between programs?
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, 开发者_JAVA技巧FILE_MAP_WRITE, 0, 0, 0, IntPtr.Zero);
// EDIT FILE CONTENTS
FlushViewOfFile(view_ptr, 0);
UnmapViewOfFile(view_ptr);
CloseHandle(m_ptr);
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.
One idea is that you could do the writes (and the FlushViewOfFile()
call) while acquiring a named mutex (which you can create by calling CreateMutex()
with a name parameter of non-NULL).
For example (error handling omitted):
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);
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).
精彩评论