2

我有一些在 .NET 应用程序的线程上创建和运行的 COM 对象。线程被标记为单线程公寓,一切似乎都在工作。我的理解是,如果这些线程尝试从主线程访问 COM 对象,那么这些对象将在 .NET 中自动为我编组和序列化,因此即使在这种情况下,事情也会为我处理,一切安全整洁,尽管可能有点慢。

我的问题是,虽然事情似乎运行良好,但我并没有在我正在创建的 STA 线程中发送消息循环。如果可以的话,我宁愿避免消息循环,因为它会导致额外的复杂性(以及可能的效率损失)。

我已经阅读了很多关于为什么需要消息循环的建议(主要来自非常有帮助的 Hans Passant),我的理解是消息循环在线程 A 上提供了一个位置,其他线程 B 可以请求 COM 对象生活在线程 A 上可以被编组和播放。如果这是正确的,那么只要没有其他线程从线程 A 上的 COM 对象请求任何内容,线程 A 在不发送消息循环时是否安全?还是在其他情况下消息循环也可能发挥作用?

我在这里玩火吗?有没有这样的情况,你问你是不是在玩火,而你不是?

4

2 回答 2

4

STA 合约需要抽出一个消息循环。但是,是的,不抽水是有可能逃脱的。有两个主要的事情可能会出错:

  • 从另一个单元(包括另一个 STA 线程或 MTA 中的线程)对接口方法进行的任何调用都不会完成。这看起来像您的程序中的死锁,调用根本不会返回。请注意,您可以很好地控制自己的调用,但您不知道 COM 组件在做什么。它很可能会启动一个线程本身。您可以使用 Debug + Windows + Threads 在调试器中看到这一点。确保您在非托管模式下运行调试器,并且您可以考虑您看到的所有线程。顺便说一句,不是特别容易。

  • 许多单元线程 COM 组件依靠消息循环来满足自己的需求。它可能是一个无害的定时器,当没有循环时它不会滴答作响。或者它可能会在内部进行编组。使用 Spy++ 并检查您的新 STA 线程是否拥有任何隐藏的窗口,如果您看到一个,肯定是有问题的迹象。诊断只是行为不端的组件。不引发事件是一种常见的不幸。

当您对服务器的内部结构知之甚少时,没有什么可钉在墙上的。一定要测试一下。

于 2012-05-19T00:43:52.393 回答
1

COM 调用可以在没有消息循环的情况下进行编组。

当您的 STA 线程正在等待某些东西时,它在大多数情况下会自动处理任何挂起的 COM 调用。

Thread.Join的文档说Blocks the calling thread [...] while continuing to perform standard COM and SendMessage pumping.

以您的名义调用的许多其他函数(CoWaitForMultipleHandles 等)也会发生同样的情况,例如当您的线程正在等待 IO 时。

于 2012-05-18T19:25:46.540 回答