17

如果我们像这样创建一个线程 STA:Thread.SetApartmentState(STA);那么它就不能运行带有[MTAThread]属性标记的代码。

我们[STAThread]在 Windows 和控制台应用程序中见过,但我从未见过带有[MTAThread]属性的代码,也不知道哪些 .NET 库使用了这个属性。

我的问题是,与具有 MTA 单元状态的线程(自然 .NET 线程)相比,单元状态设置为 STA 的线程有哪些限制?

4

2 回答 2

18

那么它就无法运行标有 [MTAThread] 属性的代码。

这不是它的工作原理。单元类型是线程的属性,而不是方法的属性。您会看到 [STAThread] 属性仅适用于 .NET 程序的 Main() 方法。它确定为运行程序而创建的第一个线程的单元类型。必要的,因为您不能在线程运行后调用 SetApartmentState()。除此之外,该属性没有任何意义,线程在其生命周期内都停留在 STA 中。您永远不会看到 [MTAThread],因为这是默认设置。

STA 线程有一些限制。它永远不会阻塞,因为这会阻塞并经常死锁任何试图调用单元线程 COM 对象的方法的代码。它必须泵送一个消息循环,以便 COM 可以编组来自另一个线程的方法调用。编组的方法调用只能在线程“空闲”时执行,而不是忙于执行任何代码。消息循环提供“不忙”状态。

对 COM 组件也有要求。它必须支持封送处理,方法是将自身限制为自动化支持的类型子集,以便可以使用标准封送处理程序。或者通过为自定义编组提供代理/存根对。HKCR\Interface\{iid}\ProxyStubClsid32注册表项确定封送处理的完成方式。

明确支持在 STA 和 MTA 线程之间共享单元线程对象。STA 线程必须创建它,MTA 线程(或其他 STA 线程)上的任何调用都会被封送。这确保了组件只看到在同一线程上进行的调用,从而确保线程安全。不需要额外的锁定。

最后但并非最不重要的一点是,如果您在 MTA 线程上创建一个单元线程 COM 对象,那么 COM 将自动创建一个 STA 线程来给它一个安全的家。唯一的失败模式是 COM 组件不支持封送处理。这样做的一个缺点是每个调用都会被编组。那很慢。

于 2010-12-25T16:24:12.933 回答
0

如果您不使用 COM,我认为这没有任何区别。如果这样做,那么在某些情况下,COM 对象可能只能从一种或另一种类型的线程访问。如果 COM 对象在两个公寓中都有效,则尝试进行性能测试。或阅读 MSDN 上的 COM 公寓。但我认为这对性能并不重要,而是一种设计选择或其他东西。

于 2010-12-25T11:12:07.150 回答