【问题标题】:COM multi-threading supportCOM 多线程支持
【发布时间】:2011-12-17 08:30:06
【问题描述】:

第一次使用 COM 我有这个 COM dll,比如 ABCServer.dll,我创建了一个 RCW 并在我的项目中添加了对它的引用。现在我的应用程序创建了几个线程,每个线程从 COM dll 创建某些类并使用它们。但是随后每个线程都在等待,而其他线程正在使用 COM dll 中的某个类。

修改我的应用程序的全部目的是在其上启用多线程。现在,当我身边发生多线程时,COM 导致它是顺序的。虽然每个线程都在创建新实例,但为什么还要等待其他线程被处理?

【问题讨论】:

  • 您的 COM 组件声明为单线程单元 (STA) 还是多线程单元 (MTA)?
  • 如何以及在哪里检查?
  • 上面写着 ThreadingModel - Apartment
  • @shf301 在那个问题上指的是this answer

标签: .net visual-studio com


【解决方案1】:

如果您的 COM 组件被标记为 STA (single-threaded apartment),那么您将无法使其成为多线程;该组件的要求是对它的所有调用都序列化到 STA 所在的线程上,并且 COM 会自动为您处理。

也就是说,如果您的组件是 STA 组件(看起来确实如此)并且您无法将其更改为 multi-threaded apartment component (MTA) 甚至更好,free-threaded(因此在公寓之间没有编组all) 因为 a) 它是用 VB6 编写的,或者 b) 它是第三方 dll,那么使用某种队列模型可能会更好。

基本上,让你的所有其他工作异步运行,然后有一个线程(或进程,由你决定),它将消耗一次调用该组件的请求,速度一样快尽可能(请注意,您可以在多个线程中实例化此组件的多个实例,您只需确保将ApartmentState property on the Thread class 设置为ApartmentState.STA),然后在调用完成时发布事件/回调并继续您的其他异步工作。

这基本上就像有两个生产者/消费者实现,一个将调用分派给 COM 组件,另一个在完成后分派结果。

【讨论】:

    【解决方案2】:

    到目前为止发布的 cmets 和答案存在相当大的混乱。 STA 或 MTA 是线程的属性。但重要的是 COM 组件需要什么。这是在 ThreadingModel 注册表值中声明的。您找到了“公寓”,这是一个非常常见的设置。这意味着该组件不支持线程。

    这与 .NET 框架中的绝大多数类没有什么不同,只有极少数是线程安全的。最大的区别在于 COM 强制线程安全。对于 .NET 类,您可以自行编写代码,以便以线程安全的方式使用类对象。这很难做到正确,并且是很难诊断错误的长期来源,但设计良好的锁定允许您绕过限制。这在 COM 是不可能的,它总是在没有你帮助的情况下提供线程安全。即使您确实想提供帮助。

    取得成功的唯一方法是仅从一个线程创建和使用 COM 组件。该线程必须使用 Thread.SetApartmentState() 初始化以选择 STA。这会阻止 COM 创建自己的线程来为组件找到安全的避风港。而且您必须抽出消息循环,这是 STA 要求。如果您不尝试从另一个线程使用 COM 组件并且组件本身不依赖于消息泵可用,这可能会很痛苦并且可能可以避免。顺便说一句,这很常见。当它停止响应时,您会注意到它需要一个,通常不会在预期时触发事件。仅从同一线程对 COM 对象进行调用,以与创建自己的对象的其他线程获得并发。这通常没有用或不可能。

    【讨论】:

      【解决方案3】:

      如果您的每个线程都在创建自己的 Apartment-model 对象实例,并且每个线程都被标记为在 STA 中运行,那么每个线程都应该在自己的单独 STA 中,并且您的 COM 对象实例应该在单独的 STA。

      我认为,这里的其他答案假设您的 COM 实例都在同一个公寓中。如果调用 Thread.SetApartmentState() 以确保每个线程在创建 COM 对象实例之前都位于 STA 中,那么该线程的 COM 对象应该位于该线程的 STA 中,该 STA 与其他线程的 STA 是分开的。然后,您应该不会看到对不同 STA 中对象的任何序列化调用。

      【讨论】:

      • 我会告诉你最新的发现,COM DLL 使用 JVM 连接到服务器并提交/接收请求/响应文件。如果我运行我的应用程序的两个实例,远程服务器日志显示创建了两个会话,而当我在我的应用程序的单个实例中使用多个请求时,JVM 日志显示请求以排队方式提交到服务器,服务器日志显示只创建一个会话。我知道可能有一百万个原因,但专家可能会导致靶心
      • 好吧,即使您所有的 COM 对象都在同一个 STA 中并且对它们的调用正在被序列化,这也不能解释为什么您只能获得一个与服务器的会话。在我看来,您的 COM 对象内部有一个逻辑,它管理每个进程的单个会话。
      • 是的,看起来是这样,当两个应用程序实例(每个都有自己的 COM 引用 DLL)运行时,会使用两个会话,而当我们在单个实例中有多个请求时只使用一个会话(使用它的 COM 参考 DLL)
      • 使用多线程假装应用程序中的多个进程的任何解决方法?
      • 我对“假装”一无所知。您可以为每个会话生成一个单独的进程,而不是使用线程,并从您的启动过程中管理它们的生命周期。现在的情况没有任何特定于 COM 的内容。无论您如何调用基于 JVM 的代码,您都会遇到同样的情况。
      猜你喜欢
      • 2012-02-27
      • 2015-12-20
      • 1970-01-01
      • 2022-01-03
      • 2023-03-26
      • 2011-10-14
      • 1970-01-01
      • 2011-03-04
      • 2018-05-29
      相关资源
      最近更新 更多