关闭已创建 STA COM 对象的线程时避免断开上下文警告

Posted

技术标签:

【中文标题】关闭已创建 STA COM 对象的线程时避免断开上下文警告【英文标题】:Avoiding disconnected context warning when shutting down a thread on which STA COM objects have been created 【发布时间】:2011-12-25 10:38:40 【问题描述】:

我正在开发一个使用 ATL 用 C++ 编写的 COM API,预计客户端将通过它的 COM 互操作工具在 C# 中使用它。目前所有的 COM 对象都只是为了支持单线程单元模型而编写的。

此 API 的某些功能会导致生成一个单独的工作线程,该线程会侦听来自服务器的事件。为了响应来自服务器的事件,该工作线程创建一些相当简单的 COM 对象,然后将这些对象传递给 COM 事件。 API 上还有其他函数会导致 API 停止侦听来自服务器的事件,然后关闭工作线程。

据我了解,STA 的规则是 STA COM 对象的代码只能在创建它的线程上运行。不幸的是,这似乎导致了断开的上下文警告,因为 .NET COM 互操作正在缓存对已在此线程上创建的所有 COM 对象的引用,并且在释放这些引用之前线程正在关闭。

我可以看到这个问题的一些潜在解决方案:

    我可以修改我们的 COM 对象以支持 MTA 线程模型,因此破坏它们的创建线程不再是问题。然而,这可能是一项相当耗时的任务,并且可能会让我遇到其他与线程相关的问题。 我可以添加一些引用计数来保持工作线程的活动状态,直到它的所有 COM 对象都被确定释放。这似乎是一种容易出错的方法。 我可以添加一个全新的线程,该线程旨在永远运行(或至少直到应用程序结束)来处理 COM 对象的创建和事件的触发。不过,为此目的使用单个线程可能会产生一些性能瓶颈,但我不太热衷于此。

上述所有方法似乎都有其缺点,所以我想知道是否有处理此类问题经验的人有任何其他方法可以提供?或者如果上述方法有我没有提到的优点或缺点?

【问题讨论】:

选项 2 对我来说听起来最明智,因为它可能需要对已经工作的代码进行最少的更改。 我同意,如果实现正确的话,它似乎确实相对容易编码并且缺点更少。不过,这似乎仍然有点像黑客,我有点希望有人能有一个干净的替代解决方案。不过我猜可能不会再有一个了。 【参考方案1】:

我最终选择了原始问题中的选项 1,并将每个 COM 对象切换为在 MTA 线程模型中运行。所有的 COM 对象只是一些数据的只读包装器,因此它们已经大部分是线程安全的,切换到 MTA 只是更新一些 .rgs 文件和一些 CoInitializeEx 调用的情况。

也许不是每个人的完美解决方案,但希望这对将来遇到此问题的任何人有所帮助。

【讨论】:

以上是关于关闭已创建 STA COM 对象的线程时避免断开上下文警告的主要内容,如果未能解决你的问题,请参考以下文章

如何将消息发布到运行消息泵的 STA 线程?

多线程公寓的目的是什么?

Lync 错误:不支持 STA 线程上的多个句柄的 waitall

ios socket一直在发送数据后台时会断开吗

从 boost::signals2 安全断开

SQL s-s-rS 对象已断开连接或在服务器上不存在