dll如何处理来自多个进程的并发性

How do DLLs handle concurrency from multiple processes?

本文关键字:进程 并发 何处理 处理 dll      更新时间:2023-10-16

我从Eric Lippert的回答中理解到"两个进程可以共享非私有内存页"。如果20个进程都加载相同的DLL,那么这些进程都共享该代码的内存页。它们不共享虚拟内存地址空间,而是共享内存。"

现在,如果硬盘上相同的DLL文件,在加载到应用程序后,将共享相同的物理内存(RAM或页文件),但映射到不同的虚拟内存地址空间,这不会使并发处理变得相当困难吗?

据我所知,c++中的并发概念更多的是关于处理线程——一个进程可以启动多个线程,每个线程可以在一个单独的核心上运行,所以当不同的线程同时调用DLL时,可能会有数据竞争,我们需要互斥,锁,信号,条件变量等。

但是DLL如何处理多进程呢?同样的数据竞赛概念也会发生,不是吗?有什么工具可以处理这个问题?还是相同的工具集吗?

现在,如果硬盘上相同的DLL文件,加载到应用程序后,将共享相同的物理内存(无论是RAM或页文件),但映射到不同的虚拟内存地址空间,这不会使并发处理相当困难吗?

正如其他答案所指出的,如果共享内存在初始化后从不写入,那么并发性问题就无关紧要了,这通常是dll的情况。如果您试图通过写入内存来改变DLL中的代码或资源,那么很有可能您在某个地方有一个坏指针,最好的办法是由于访问冲突而崩溃。

然而,我也想简单地跟进你的关注:

…映射到不同的虚拟内存地址空间…

在实践中,我们非常努力地避免这种情况发生,因为当它发生时,在第一次加载代码页时可能会出现严重的用户明显的性能问题。(当然,工作集可能会大量增加,这会导致其他性能问题。)

DLL中的代码通常包含硬编码的虚拟内存地址,假设代码将加载到编译时已知的虚拟内存"基"地址中。如果在运行时违反了这个假设(例如,因为已经存在另一个DLL),那么所有这些硬编码地址都需要在运行时打补丁,这是非常昂贵的。

如果您想了解历史细节,请参阅Raymond关于该主题的文章:https://blogs.msdn.microsoft.com/oldnewthing/20041217-00/?p=36953/

DLL包含多个"段",每个段都有一个描述符告诉Windows它的Characteristics。这是一个32位DWORD。代码段显然设置了代码位,通常也设置了可共享位。只读数据也可以是可共享的,而可写数据通常没有可共享标志。

现在,可以在额外的段上设置不同寻常的特征组合:可写可共享。这不是默认值,而且确实可能导致竞争条件。所以你的问题的最终答案是:这个问题主要是通过段的默认特征来避免的,其次,任何具有非标准特征的段的DLL都必须处理自己造成的问题。