我有一些COM对象,我正在.NET应用程序中的线程上创建和运行。线程被标记为Single Threaded Apartments,一切似乎都在运作。我的理解是,如果这些线程试图从主线程访问COM对象,那么这些对象将在.NET中自动被封送和序列化,所以即使在这种情况下,也会为我处理事情,一切都安全可靠,尽管可能有点慢。
我的问题是,虽然事情似乎工作得很好,但我不在我创建的STA线程中抽取消息循环。如果可以的话,我宁愿避免使用消息循环,因为它会导致额外的复杂性(以及可能的效率损失)。
我已经阅读了一些关于为什么消息循环是必要的建议(主要来自非常有用的Hans Passant),我的理解是消息循环在线程A上给出了一个其他线程B可以请求的位置生活在线程A上的COM对象可以被编组并使用。如果这是正确的,那么只要没有其他线程从线程A上的COM对象请求任何东西,线程A是否安全,不会引发消息循环?或者还有其他情况,消息循环也可能发挥作用?
我在这里玩火吗?有没有一个案例你会问你是不是在玩火而你不是?
答案 0 :(得分:4)
STA合同要求抽取消息循环。但是,是的,有可能逃脱不抽水。有两件大事可能出错:
对来自其他公寓的接口方法进行的任何调用,包括另一个STA线程或MTA中的线程都无法完成。这看起来像程序中的死锁,调用根本就不会返回。请注意,您可以很好地控制自己的调用,但是您不知道COM组件正在做什么。它可能会启动一个线程本身。您可以在调试器中使用Debug + Windows + Threads看到这一点。确保以非托管模式运行调试器,并且可以考虑所看到的所有线程。不是特别容易btw。
许多公寓的线程COM组件都依赖于消息循环来满足自己的需求。它可能是一个无害的定时器,当没有循环时它不会打勾。或者它可以在内部进行编组。使用Spy ++并检查您的新STA线程是否拥有任何隐藏的窗口,如果您看到它,请确定有问题。诊断是组件行为不端。不引发事件是一种常见的事故。
当你对服务器的内部结构不够了解时,没有什么可以钉在墙上。一定要测试一下它。
答案 1 :(得分:1)
COM调用可以在没有消息循环的情况下进行编组。
当您的STA线程正在等待某些事情时,它会在大多数情况下自动处理任何挂起的COM调用。
Thread.Join的文档说Blocks the calling thread [...] while continuing to perform standard COM and SendMessage pumping.
对于代表您调用的许多其他函数(CoWaitForMultipleHandles等)也会发生同样的情况,例如:当你的线程在等待IO时。