【问题标题】:Use COM STA or MTA Without Shared COM Objects?在没有共享 COM 对象的情况下使用 COM STA 或 MTA?
【发布时间】:2019-09-10 04:08:41
【问题描述】:

This thread 非常擅长解释 COM 的 STA 与 MTA,但它没有解决如何编写代码或何时使用其中一个,而仅讨论了线程安全使用的 COM 单元的技术细节对象与否。我敢打赌,大多数用户只是想知道如何通过 COM 使用 Win API,而无需在多个线程之间共享任何 COM 对象。

如果您的 COM 对象不在线程之间共享,并且您的代码使用多个线程或单个线程,每个线程都有自己的 COM 对象实例,并且没有共享对象,您是否应该始终使用 STA?这取决于您使用的对象吗?如果您不总是使用 STA,那么您何时使用 MTA?在这种情况下,您是否需要消息泵?

在我的例子中,我使用来自主 GUI 线程(使用 Qt 框架)的 Task Scheduler API (ITaskService) 和 Shell Links/Create Shortcut API (IShellLink),以及来自 a工作线程。

在初始化和使用 COM 对象之前,我从每个线程调用 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);,之后调用 CoUninitialize();。这是 COM 的正确用法吗?在没有工作线程的情况下使用来自主 GUI 线程的 COM 对象是否同样适用?

【问题讨论】:

  • 在理想世界中,作为线程所有者,您不应该关心(抛开跨单元调用可能存在的性能问题)您使用的 COM 服务器是 STA 还是 MTA。这基本上就是所有这些 COM 线程的全部意义,它应该是一个 功能 而不是负担......不幸的是,大多数 shell 对象(和其他......)只是不提供必要的对象(tlb,代理等)来编组公寓之间的调用(确切的原因对我来说仍然是模糊的,除了微软的兼容性问题......)。所以你必须关心...对于这些对象,无论是否共享,你必须创建一个 STA 线程。
  • 选择STA是一个承诺,穿越你的心希望死。永远不要阻塞和泵送消息循环,您知道何时要这样做。您希望可以撒谎,并希望在谎言造成麻烦时死去。结果通常没问题,您的程序将死锁,或者您希望引发的事件不会触发。不能保证,也不容易诊断,这是他们在您致电 Microsoft 支持时快速让您挂断电话的方式。或者。如果你打算在 shell 接口上撒谎,那么你还需要在 Win7 上进行测试。
  • @Simon 那么始终使用 STA 是否安全?
  • 如果您使用的是 Shell 对象,这可能是最安全的方式。但没有任何事情可以保证。

标签: c++ multithreading winapi com


【解决方案1】:

为了对您通过 CoCreateInstance 实例化的对象进行出站 COM 调用,STA 应该足够好,并且对于您的 GUI 线程(具有 GetMessage/DispatchMessage 循环的线程)来说几乎是必须的。

当托管您自己的线程安全 COM 对象时,MTA 开始变得相关,这些对象预计会从其他进程中调用。

The documentation for IFileOperation 声明:

IFileOperation 只能在单线程单元中应用 (STA)情况。它不能用于多线程单元 (MTA) 情况。对于 MTA,您仍然必须使用 SHFileOperation。

查看全部,此链接:INFO: Calling Shell Functions and Interfaces from a Multithreaded Apartment

我怀疑文档真正想说的是:

  1. 实现 IFileOperation 的类不是线程安全的
  2. 它的 ThreadingModel 在注册表中被声明为“apartment”,如果从 MTA 线程访问,则会产生编组开销。

在我们的应用程序中,在主 STA 线程上使用了 ITaskScheduler。我们在拥有自己的消息泵的后台 STA 线程上使用 IFileOperation。

我认为非常有用的其他一些链接:

https://support.microsoft.com/en-us/help/150777/info-descriptions-and-workings-of-ole-threading-models

https://devblogs.microsoft.com/oldnewthing/?p=22603

【讨论】:

  • 谢谢塞尔比。因为我使用的是 Qt,所以我不必使用 GetMessage/DispatchMessage 手动创建消息泵,对吗?此外,在线程之间不共享 COM 对象的情况下始终使用 STA 是否 100% 安全?不想要任何问题! :)
  • QT 框架会在主线程上为你“推送消息”。所以你在那里很好。我不确定我是否理解你的最后一个问题。您能否详细说明“使用 STA 而不在线程之间共享 COM 对象”是什么意思?
  • 我的意思是,只要我不在我的 GUI 和工作线程之间共享我的 COM 对象,将它们隔离在每个线程中,在每个线程上初始化 COM 时仅使用 STA 是否 100% 安全?
  • 是的,我认为您可以进行出站 COM 调用。
  • 我是否需要在工作线程之前在主 GUI 线程上初始化 COM,以便 COM 将其视为带有消息泵的 GUI 线程?我隐约记得在某处读到过有关这方面的内容。还是顺序无关紧要...
猜你喜欢
  • 2015-03-03
  • 1970-01-01
  • 1970-01-01
  • 2011-04-13
  • 2014-02-22
  • 1970-01-01
  • 2018-03-21
  • 2018-09-04
  • 2013-10-15
相关资源
最近更新 更多