【问题标题】:How to automatically initialize / uninitialize something globally for every thread?如何为每个线程全局自动初始化/取消初始化某些东西?
【发布时间】:2013-09-14 22:46:00
【问题描述】:

我有一个带有initializationfinalization 部分的单元。该单元包含一个复杂对象,该对象在initialization 中实例化并在finalization 中销毁。但是,此对象还包含一个 ADO 连接。这使得跨线程使用它时成为一个问题,因为 ADO 是 COM,并且需要为每个线程初始化。

这是我目前处理这个全局对象实例的方式:

uses
  ActiveX;
...
initialization
  CoInitialize(nil);
  _MyObject:= TMyObject.Create;
finalization
  _MyObject.Free;
  CoUninitialize;
end.

这仅适用于主线程。任何其他线程都无法访问它,并会返回异常CoInitialize has not been called

如何解决这个问题以使这个单元线程安全?我需要一种方法来挂钩创建的任何线程的每次创建/销毁,并且每个线程都需要引用该对象的不同实例。但是如何去做呢?

【问题讨论】:

  • 您希望每个线程调用 CoInitialize?因此,进行下一个合乎逻辑的步骤并从每个线程调用 CoInitialize。

标签: multithreading delphi initialization delphi-xe2 ado


【解决方案1】:

好吧,正如您自己所说,每个线程都需要分别调用CoInitialize。另外,每个线程也需要有自己的ADOConnection

我认为您需要放弃使用该单元中的单个全局对象/连接的想法。只需在每个线程中重复该对象的创建和销毁。当线程类型不同时,您可以在它们之上设计一个基本线程类。如果对象太大(与线程有关的开销)或不完全“适合”线程,则拆分对象设计。

现在,您的问题听起来只是想保持方便,但如果确实需要集中 ADO 连接参与,那么也许您可以为主线程和其他线程的连接事件实现多播事件.对于连续连接,登录应该不是问题:只需存储登录值并将它们提供给线程即可。

【讨论】:

    【解决方案2】:

    虽然另一种设计可能是更好的解决方案,但您可以将 _MyObject 声明为 threadvar 以便为每个线程拥有一个单独的实例。另外你可以将 CoInitialize/CoUnitialize 移动到 TMyObject 的构造函数/析构函数中。

    我无法就何时创建​​和释放这些实例提供建议,因为我不知道您的线程是如何创建和释放的。

    【讨论】:

    • @NGLN 该声明不相关。这甚至不是真的。您可以拥有作为指针的线程变量。您可以拥有过程类型的线程变量。
    • @DavidHeffernan 实际上,RTL/VCL 充满了将对象实例或过程类型声明为 threadvar 的示例。 System.Classes.TThread 中甚至还有一个私有类threadvar。似乎文档在这里具有误导性。
    • @David 可惜another docs page 没有提到指针变量,但我可以得出结论,每个线程实例都不会自动创建和销毁吗? IE。声明还不够:您还需要手动处理?
    • @NGLN IIRC threadbare 初始化为零,但从不离开范围。因此,除非您明确完成,否则它们会泄漏。
    猜你喜欢
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-17
    • 1970-01-01
    • 2017-06-17
    • 2011-07-20
    相关资源
    最近更新 更多