Q:

How do DLLs handle concurrency from multiple processes? 

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? 

A:

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/

A:

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.