STA 线程模型问题





4.00/5 (6投票s)
描述 STA 线程问题
引言
在用 STA 线程模型编程时,我认为开发人员应该注意两点。我不是试图涵盖可能遇到的所有陷阱,而只是针对我认为可能困扰开发人员的两个特定问题。
项目:“为某个或某种目的创建一个 ActiveX 组件。”
首先,我使用“Apartment”线程模型开始了一个简单的 ActiveX 组件。然后添加了另一个 COM 类,它将作为参数传递给其中一个事件。创建了一个事件线程来向客户端触发事件。一切似乎都运行良好。我编写了各种简单的应用程序来测试 ATL/WTL、MFC、VB 和 VBScript/JScript 中的功能,所有这些都使用相同的线程模型。
STA 死锁
然后我尝试了 MTA 用于容器。突然,它开始随机死锁。为什么?我想如果它适用于 STA,那么容器是 STA 还是 MTA 有什么区别呢? COM 应该介入并处理 apartment 不兼容性。我花了一些时间研究才找到问题所在。感谢 Valery Pryamikov 在 ATL 列表中的帖子,“用 COM+ 技术设计解决方案”(第 96-97 页)和“事务性 COM+”(第 130-131 页),事情开始变得有意义。我制作了一个精简版本,显示了问题,您可以在此处下载 STA 死锁 示例项目。请在调试器中运行它。当您退出应用程序时,死锁将会发生。请注意,如果您将客户端的线程模型更改为“Apartment”或将进程内 COM 服务器更改为“Both”,则一切正常。问题出在客户端在事件函数的调用中向 COM 组件发出回调。现在,如果同时客户端出于任何原因回调主组件并使用消息循环阻塞(即在 Unadvise
被调用时关闭组件中的事件线程),就会发生死锁。当客户端回调 ISimpleObj
方法时,“通道”已经被 Unadvise
占用,我在那里尝试关闭事件线程。因此,两个线程将互相等待对方获得“通道”。这只是死锁可能发生的一个场景,并且很容易通过其他方式完成。关于这一点,令人讨厌的是它可能不会一直发生,也可能根本不会发生。这完全取决于正确的情况。所以要小心。
STA 可重入性
众所周知,但我只是想展示它,因为我从未在开始使用 COM 时看到具体的例子。也许有人会觉得它有帮助。因此,在处理死锁之后,我受到了 STA 可重入性的影响。该组件使用 Windows 套接字与服务器通信。现在,我已经将我的组件标记为“Both”并同步了对组件的所有访问,我以为我安全了……但是……其中一个方法需要一个接口指针,该指针属于某个对象的一部分。现在,在方法内部,我调用接口上的方法并通过套接字发送数据。不幸的是,当我在另一个组件上进行传出调用时,“STA 可重入模型”将把线程让给另一个传入调用(如果有的话)。如果客户端决定从与对象的创建线程不同的线程调用我的方法,则可能会发生这种情况。我不能假设客户端会做正确的事情。因此,这是不可接受的,因为我的组件通过套接字与之通信的实际服务器期望特定的信息流。我制作了一个简单的项目,该项目使用文件而不是套接字来演示它。如果您运行它,请查看 STA 可重入性,您会看到输出到日志文件的内容是混合的,而不是具有顺序流程。请注意,如果将客户端的线程模型更改为 MTA,它将运行良好。 COM 将介入并为我们处理同步。
在处理完“Apartment”、“Both”和“Free”之后,如果可能的话,我宁愿选择 MTA 而不是 STA 模型。我希望有人觉得这篇文章有帮助。