Delphi DLL - 线程安全

8
我有一个Delphi DLL,我想在我的应用程序中的一个线程(或多个线程)中加载它。DLL只是创建一个对象,然后使用它并销毁它。从这个角度来看,DLL代码是线程安全的。
但是如果我将该DLL加载到线程中会发生什么?该DLL是否仍然是线程安全的?关于线程加载DLL,我应该知道什么?我已经看到VCL具有IsMultThread属性,当我们创建线程时设置它,但是DLL会收到通知吗?还是我需要手动执行此操作?
3个回答

13
最常见的陷阱是使用全局变量。只要不使用任何全局变量(或正确同步访问您使用的变量),您就可以远离线程安全问题。
例如,内存管理器使用IsMultiThread来在单线程情况下进行优化。个人认为这不是一种值得做的优化,因为几乎所有有用的代码都有某种形式的线程。我会在DLL的开头设置IsMultiThread为True,例如在DLL的.dpr文件中的begin/end块中,或者在一个单位的初始化部分中,它们都是相同的。
直接回答您的问题,除非您在DLL中创建了一个线程,否则DLL中的IsMultiThread实例将不会被设置为True。既然您在EXE中创建线程,那么您需要在DLL中自己创建线程。
更普遍地说,如果不知道代码执行的功能和“线程安全”具体指什么,很难对代码的线程安全性做出具体判断。后一点听起来有些奇怪,但我所指的是Eric Lippert在他著名的What is this thing you call "thread safe"?文章中所讨论的问题。

好的。假设这个dll调用了一个应用程序回调,只要回调不使用任何全局变量,它会在线程上工作吗? - Rafael Colucci
@Rafael 我不知道,这比在 Stack Overflow 评论中表达的更复杂! - David Heffernan
好的。那么,我应该像对待我的应用程序一样对待我的dll,对吧?没什么大不了的,只需要将dll作为exe使其线程安全即可。 - Rafael Colucci
@Rafael 正确。从这个角度来看,DLL与EXE没有任何区别。它只是被加载到您的进程中的代码。 - David Heffernan
哇,你真是救了我很多时间。我将线程实例化从Delphi移动到封装的C#代码中,结果它开始在奇怪的位置崩溃。加一! - Milosz Krajewski

8
在您的库项目的主块中,首先将IsMultiThread设置为True
library MyLibrary;
begin
  IsMultiThread := True;
  ...
end.

这将指示内存管理器使用线程安全的分配/释放例程。

2
如果您在线程中小心操作,就不会有问题。如果需要更新主线程的VCL,请使用synchronize,或者更好的方法是不要这样做。
我有一个大型DLL,在其中进行大量数据库访问,并在一个线程中运行。在我的单元测试中一切都很好,但在主应用程序的线程中运行时出现了严重问题。结果发现,我必须重新阅读关于线程安全的数据库文档。在我的情况下,这是DBISAM,我必须确保为线程化的数据库实例创建一个新会话,以避免与主会话冲突。
另一个我遇到麻烦的地方(同样在单元测试中效果很好,在线程中失败)是XML处理。我必须在使用XML DOM之前/之后调用CoInitialize/CoUninitialize。这也适用于任何使用XML DOM的SOAP内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接