2
votes

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.

4
Since file mappings backed by the same file are guaranteed to be coherent within a process (with the exception of remote files), I don't see why pointer1 cannot point to the same block of memory as pointer2. In fact, both pointers being identical is the most straight forward way to implement the coherency guarantee. There is no documented guarantee either way (with respect to identity of the pointers), though. - IInspectable
There is no reason why the mappings would result in the same pointer: mapped/unmapped separately, different handles on the backend. Expected is that you always get two different pointers being mapped to the same physical memory. - Roman R.
Also, in your code snippet you supposedly wanted file2 to be an argument for getting fileMapping2, not file1 (copy/paste thing). The same thing on the following line. - Roman R.
@RomanR. yeah copy paste error - ratchet freak
@Roman MapViewOfFile specifically calls out that "file views derived from any file mapping object that is backed by the same file are coherent". Neither file mapping objects nor file handles need to be shared. I also do not understand the part in your comment that says: "You always get two different pointers being mapped to the same physical memory." - IInspectable

4 Answers

2
votes

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.

1
votes

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.

1
votes

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).

1
votes

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.