STA线程相比MTA线程有哪些限制?

17
如果我们将线程设置为STA,方法如下:Thread.SetApartmentState(STA);,那么它将无法运行带有[MTAThread]属性标记的代码。
在Windows和控制台应用程序中,我们经常看到[STAThread],但我从未见过使用[MTAThread]属性标记的代码,也不知道哪些.NET库使用此属性标记。
我的问题是,与MTA公寓状态(自然.NET线程)相比,具有STA公寓状态设置的线程的限制是什么?
2个回答

18
那不是它的工作方式。公寓类型是线程的属性,而不是方法的属性。您只在应用于.NET程序的Main()方法中看到[STAThread]属性。它确定创建用于运行程序的第一个线程的公寓类型。这是必需的,因为您无法在线程正在运行之后调用SetApartmentState()。除此之外,该属性没有其他含义,线程将在其生命周期内保持STA。您从未见过[MTAThread],因为这是默认设置。
STA线程有一些限制。它永远不能阻塞,因为这会阻塞并常常死锁任何试图调用公寓线程化COM对象的方法的代码。并且它必须泵送消息循环,以便COM可以将方法调用从另一个线程封送。封送的方法调用只能在线程处于“空闲”状态时执行,而不是忙于执行任何代码。消息循环提供了这种“非忙碌”状态。
COM组件也有要求。它必须支持封送,要么通过限制自身仅使用Automation支持的类型子集,以便可以使用标准封送程序。要么通过为自定义封送提供代理/存根对。HKCR \ Interface \ {iid} \ ProxyStubClsid32注册表键确定如何进行封送。
在STA和MTA线程之间共享公寓线程化对象是明确支持的。 STA线程必须创建它,MTA线程(或其他STA线程)上的任何调用都会被封送。这确保组件仅在同一线程上看到调用,从而确保线程安全。不需要额外的锁定。
最后但并非最不重要的是,如果您在MTA线程上创建公寓线程化的COM对象,则COM将自动创建一个STA线程,并为其提供安全的家园。这种方式的唯一故障模式是当COM组件不支持封送时。以这种方式执行的唯一缺点是每次调用都将被封送。这很慢。

2
MTAThread只在C#中是默认的。在VB.NET中,STAThread是默认的。只是说一下...因为我花了很长时间才找到这个。 - DanielG
这适用于VB.NET控制台模式项目。顺便说一下,这是对STA要求的严重违反,STA线程必须进行泵操作。VB程序员在编写多线程代码时往往运气不佳,Form类的默认实例是另一个主要陷阱。也许这一切都是有意为之 :) - Hans Passant

0

我认为如果你不使用COM,也不会有任何区别。但是在某些情况下,仅能从一种类型的线程访问COM对象。如果COM对象可以在两种单元中使用,则可以尝试进行性能测试。或者在MSDN上阅读关于COM单元的相关内容。但是我认为这并不影响性能,而更多的是设计选择或其他因素。


我使用一些 COM 组件,需要 STA。改变公寓状态可以满足我的需求,但我不确定后果。在 ASP.NET 应用程序中,一个 STA 线程和一个 MTA 线程共享一个对象。 - Xaqron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接