0
votes

I understand from Eric Lippert's answer that "two processes can share non-private memory pages. If twenty processes all load the same DLL, the processes all share the memory pages for that code. They don't share virtual memory address space, they share memory."

Now, if the same DLL file on the harddisk, after loaded into appliations, would share the same physical memory (be it RAM or page files), but mapped to different virtual memory address spaces, wouldn't that make it quite difficult to handle concurrency?

As I understand, concurrency concept in C++ is more about handling threading -- A process can start multiple threads, each can be run on an individual core, so when different threads calls the DLL at the same time, there might be data racing and we need mutex, lock, signal, conditional variable and so on.

But how would a DLL handles multi-processes? The same concept of data racing will happen, isn't it? What are the tools to handle that? Still the same toolset?

2
Concurrency is only a problem when you share writable data. That's not happening here. - Kerrek SB
I believe the pages are shared copy-on-write. So if there is mutable state inside of the DLL (as opposed to just code), each process will get its own version of the page. (Not familar enough with Windows to know if that is even possible, or the DLL memory is read-only altogether). - Thilo
@KerrekSB so a DLL cannot have memory of its own that is writable? all memory a DLL is handling, is owned by the process? - athos
Related (the answer mentions copy-on-write for mutable state): stackoverflow.com/questions/17374983/… - Thilo
@athos: It depends on what you mean by "a DLL can have". A process can of course have memory. A DLL is just a source of instructions (and initial data). The same instructions can be executed by multiple processes. The optimization comes from mapping the same piece of real memory that contains the instructions to multiple different virtual address spaces of different processes, without duplicating the real memory contents. Data (global variables) could also be shared if it's read-only, but if it's writable, each process will of course have to get its own, distinct copy. - Kerrek SB

2 Answers

5
votes

Now, if the same DLL file on the hard disk, after loaded into applications, would share the same physical memory (be it RAM or page files), but mapped to different virtual memory address spaces, wouldn't that make it quite difficult to handle concurrency?

As other answers have noted, the concurrency issues are of no concern if the shared memory is never written after it is initialized, which is typically the case for DLLs. If you are attempting to alter the code or resources in a DLL by writing into memory, odds are good you have a bad pointer somewhere and the best thing to do is to crash with an access violation.

However I wanted to also briefly follow up on your concern:

... mapped to different virtual memory address spaces ...

In practice we try very hard to avoid this happening because when it does, there can be a serious user-noticeable performance problem when loading code pages for the first time. (And of course a possible large increase in working set, which causes other performance problems.)

The code in a DLL often contains hard-coded virtual memory addresses, on the assumption that the code will be loaded into a known-at-compile-time virtual memory "base" address. If this assumption is violated at runtime -- because there's another DLL already there, for example -- then all those hard-coded addresses need to be patched at runtime, which is expensive.

If you want some historical details, see Raymond's article on the subject: https://blogs.msdn.microsoft.com/oldnewthing/20041217-00/?p=36953/

2
votes

DLL's contain multiple "segments", and each segment has a descriptor telling Windows its Characteristics. This is a 32 bits DWORD. Code segments obviously have the code bit set, and generally also the shareable bit. Read-only data can also be shareable, whereas writeable data generally does not have the shareable flag.

Now you can set an unusual combination of characteristics on an extra segment: writeable and shareable. That is not the default, and indeed might cause race conditions. So the final answer to your question is: the problem is avoided chiefly by the default characteristics of segments, and secondly any DLL which has a segment with non-standard characteristics must deal with the self-inflicted problems.