Question

If I create 2 separate mappings of the same file in the same process will the pointers be shared?

in other words:

LPCTSTR filename = //...

HANDLE file1 = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0);
HANDLE fileMapping1 = CreateFileMapping(file1, NULL, PAGE_READONLY, 0, 0, 0);
void* pointer1 = MapViewOfFile(fileMapping1, FILE_MAP_READ, 0, 0, 0);

CloseHandle(fileMapping1);
CloseHandle(file1);

HANDLE file2 = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0);
HANDLE fileMapping2 = CreateFileMapping(file2, NULL, PAGE_READONLY, 0, 0, 0);
void* pointer2 = MapViewOfFile(fileMapping2, FILE_MAP_READ, 0, 0, 0);

CloseHandle(fileMapping2);
CloseHandle(file2);

Will pointer1 ever be equal to pointer2?

The reason I am asking is that I have several threads that need to search in a large (300+MB) file and I want to use memory mapping for that. However the process needs to be able to run on an old 32bit xp machine, so if each thread allocated their own copy in virtual memory then I could run out of memory.

Was it helpful?

Solution 2

Will pointer1 ever be equal to pointer2?

The pointers might be the equal in case MapViewOfFile chooses the same address for the mapping. You don't control this with MapViewOfFile, and you have some control over this with MapViewOfFileEx (last argument lpBaseAddress there).

Each separate MapViewOfFile can create a new mapping over the same physical data, so OS does not need to map the file mapping into the same addresses even if you open two mappings simultaneously, preserving the coherence of data. It is easy to see this by modifying your code slightly:

HANDLE file1 = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
HANDLE fileMapping1 = CreateFileMapping(file1, NULL, PAGE_READWRITE, 0, 0, 0);
void* pointer1 = MapViewOfFile(fileMapping1, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

//CloseHandle(fileMapping1);
//CloseHandle(file1);

HANDLE file2 = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
HANDLE fileMapping2 = CreateFileMapping(file2, NULL, PAGE_READWRITE, 0, 0, 0);
void* pointer2 = MapViewOfFile(fileMapping2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);

INT& n1 = *((INT*) pointer1);
INT& n2 = *((INT*) pointer2);

ATLASSERT(&n1 != &n2);  // The pointers are not equal even though they point 
            // the same data!
INT n3 = 0;
n1 = 2;
n3 += n2;
n1 = 3;
n3 += n2;
ATLASSERT(n3 == 5); // That's 2+3 we wrote through n1 and read through n2

//CloseHandle(fileMapping2);
//CloseHandle(file2);

That is, pointer equivalence is not something you should expect or rely on. Especially if your mapping is large, and reopening does not take place immediately.

OTHER TIPS

msdn has documented it between the lines:

As mentioned above, you can have multiple views of the same memory-mapped file, and they can overlap. But what about mapping two identical views of the same memory-mapped file? After learning how to unmap a view of a file, you could come to the conclusion that it would not be possible to have two identical views in a single process because their base address would be the same, and you wouldn't be able to distinguish between them. This is not true. Remember that the base address returned by either the MapViewOfFile or the MapViewOfFileEx function is not the base address of the file view. Rather, it is the base address in your process where the view begins. So mapping two identical views of the same memory-mapped file will produce two views having different base addresses, but nonetheless identical views of the same portion of the memory-mapped file.

Also:

The point of this little exercise is to emphasize that every view of a single memory-mapped file object is always mapped to a unique range of addresses in the process. The base address will be different for each view. For that reason the base address of a mapped view is all that is required to unmap the view.

MapViewOfFile finds a hole in your process's address space that is big enough for the entire file. I would not expect it to return the same pointer even if you passed the same file mapping object twice. For different mapping objects and different file handles, I would definitely expect the pointers to be different.

Behind the scenes, Windows should be using the same 'section' object, so both ranges of virtual address space should be mapped to the same physical memory. This is the same as two processes mapping the same file.

To use the same memory range from both threads, one thread will have to map the file and store the pointer in a shared location. The other thread will have to retrieve that pointer from the shared location. You're likely to need reference counting to decide when to unmap the file (which you do by calling UnmapViewOfFile - closing the file mapping handle will not release that address space).

The same physical memory will be used, but the two pointers will likely not be the same. In any case, you have no guarantee that they will be the same, even if they incidentially are when you test. Read as: you cannot ever rely on the assumption that this will be the case.

You are creating two mappings on two different file handles. Incidentially they refer to the same file (which is why the same physical memory will be used), but they are still two different mappings that do not logically relate to each other in any way.

Yes, it may sound illogical and unreasonable (maybe even impossible) to have the same physical memory at two different addresses. However, this is a perfectly legitimate thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top