【问题标题】:Is STA Message Loop Required in This Case?这种情况下需要STA消息循环吗?
【发布时间】:2012-05-26 02:45:08
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你有活动吗?您是否可以控制事件处理程序以确保它们的重新进入调用不会导致无限递归?如果您有消息泵,通常使用发布消息来打破这个循环。
  • 我想我不知道与此相关的问题。什么会导致在我创建的线程中引发事件而没有其他人正在查看?我正在使用的 COM 对象?据我所知,他们没有引发任何事件......
  • 如果您的 COM 对象的设计包括通知外部世界正在发生的事情,您就可以实现像 IConnectionPointContainer 这样的传出事件接口。

标签: .net multithreading com sta


【解决方案1】:

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

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

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

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

【讨论】:

  • 一如既往的有见地的回答。非常感谢。
  • 我猜CDO.Message COM 对象也有类似的问题。当用户随意移动 MDI 窗口时,它从未从 Send() 返回。可能是因为它依赖于消息队列,并且无法将消息发布到其中,因为所有窗口移动的队列都已满,并且实现忘记检查 PostMessage 是否失败。
【解决方案2】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    相关资源
    最近更新 更多