我从Eric Lippert's answer了解到,"两个进程可以共享非私有内存页面。如果20个进程都加载了相同的DLL,则进程都共享该代码的内存页面。他们不共享虚拟内存地址空间,他们共享内存。"
现在,如果加载到appliations中的硬盘上的相同DLL文件将共享相同的物理内存(无论是RAM还是页面文件),但是映射到不同的虚拟内存地址空间,那么就不会处理并发很困难吗?
据我所知,C ++中的并发概念更多是关于处理线程 - 一个进程可以启动多个线程,每个线程都可以在一个单独的核心上运行,所以当不同的线程同时调用DLL时,可能会有数据赛车,我们需要互斥锁,锁,信号,条件变量等。
但是DLL如何处理多进程?数据竞赛的概念将会发生,不是吗?有哪些工具可以解决这个问题?仍然是相同的工具集?
答案 0 :(得分:5)
现在,如果硬盘上的相同DLL文件在加载到应用程序后会共享相同的物理内存(无论是RAM还是页面文件),但是映射到不同的虚拟内存地址空间,那不是是否很难处理并发?
正如其他答案所指出的那样,如果共享内存在初始化之后永远不会被写入,则并发问题无关紧要,这通常是DLL的情况。如果你试图通过写入内存来改变DLL中的代码或资源,那么你可能会在某处遇到错误的指针,而最好的办法就是在访问冲突时崩溃。
但是我想简要介绍一下你的问题:
...映射到不同的虚拟内存地址空间......
在实践中,我们非常努力地避免这种情况发生,因为当它发生时,第一次加载代码页时可能会出现严重的用户注意到的性能问题。 (当然,工作集可能会大幅增加,这会导致其他性能问题。)
DLL中的代码通常包含硬编码的虚拟内存地址,前提是代码将被加载到编译时已知的虚拟内存中。#34; base"地址。如果在运行时违反了这个假设 - 例如,那里已经存在另一个DLL - 那么所有那些硬编码的地址都需要在运行时进行修补,这是很昂贵的。
如果您需要一些历史细节,请参阅Raymond关于此主题的文章:https://blogs.msdn.microsoft.com/oldnewthing/20041217-00/?p=36953/
答案 1 :(得分:2)
DLL包含多个"段",每个段都有一个描述符告诉Windows Characteristics
。这是一个32位的DWORD。代码段显然具有代码位设置,通常也是可共享位。只读数据也可以是可共享的,而可写数据通常没有可共享标志。
现在,可以在额外的细分上设置一个不寻常的特征组合:可写和可共享。这不是默认值,实际上可能会导致竞争条件。因此,问题的最终答案是:主要通过段的默认特征来避免问题,其次,任何具有非标准特征的段的DLL都必须处理自己造成的问题。