DLL 如何处理来自多个进程的并发?

Posted

技术标签:

【中文标题】DLL 如何处理来自多个进程的并发?【英文标题】:How do DLLs handle concurrency from multiple processes? 【发布时间】:2016-09-26 00:31:55 【问题描述】:

我从Eric Lippert's answer 了解到,“两个进程可以共享非私有内存页面。如果 20 个进程都加载相同的 DLL,则这些进程都共享该代码的内存页面。它们不共享虚拟内存地址空间,它们共享内存。”

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

据我了解,C++中的并发概念更多的是处理线程——一个进程可以启动多个线程,每个线程都可以运行在一个单独的内核上,所以当不同的线程同时调用DLL时,可能会有数据赛车,我们需要互斥体、锁、信号、条件变量等等。

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

【问题讨论】:

只有在共享可写数据时才会出现并发问题。这不会发生在这里。 我相信这些页面是共享的写时复制。因此,如果 DLL 内部存在可变状态(而不仅仅是代码),每个进程都会获得自己的页面版本。 (对 Windows 不够熟悉,不知道这是否可能,或者 DLL 内存完全是只读的)。 @KerrekSB 所以DLL不能拥有自己的可写内存? DLL 正在处理的所有内存都归进程所有? 相关(答案提到了可变状态的写时复制):***.com/questions/17374983/… @athos:这取决于您所说的“DLL 可以拥有”是什么意思。 进程当然可以有内存。 DLL 只是指令(和初始数据)的来源。相同的指令可以由多个进程执行。优化来自将包含指令的同一块真实内存映射到不同进程的多个不同虚拟地址空间,而不复制 真实 内存内容。如果数据(全局变量)是只读的,也可以共享它,但如果它是可写的,那么每个进程当然必须获得自己的不同副本。 【参考方案1】:

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

正如其他答案所指出的,如果共享内存在初始化后从未被写入,则并发问题是无关紧要的,这通常是 DLL 的情况。如果您试图通过写入内存来更改 DLL 中的代码或资源,则很有可能您在某处有一个错误的指针,最好的办法是因访问冲突而崩溃。

不过,我还想简要跟进您的问题:

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

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

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

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

额外段,可写可共享?有趣的! msdn.microsoft.com/en-us/library/ms809762.aspx 中也有描述吗? @athos:不。Matt Pietrek 文章的读者不是普通的开发人员;他们可以弄清楚其中的含义。对于普通的开发人员,有例如msdn.microsoft.com/en-us/library/h90dkhs0(v=vs.90).aspx。 (我再说一遍:你用这个想法遇到的可预见的问题是自己造成的;不要告诉我们我们没有警告你)

以上是关于DLL 如何处理来自多个进程的并发?的主要内容,如果未能解决你的问题,请参考以下文章

flask如何处理并发

如何处理两个进程之间的进程间通信?

iis如何处理并发请求

Nginx是如何处理一个请求

如何处理死锁

Nginx如何处理一个连接