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

如果我们像这样创建一个线程STA: Thread.SetApartmentState(STA); 然后它无法运行标有[MTAThread]属性的代码。

我们在Windows和控制台应用程序中看到[STAThread] ,但我从未见过具有[MTAThread]属性的代码,并且不知道哪些.NET库使用此属性。

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

然后它无法运行标有[MTAThread]属性的代码。

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

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

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

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

最后但并非最不重要的,如果您在MTA线程上创建一个公寓线程COM对象,那么COM将自动创建一个STA线程,为其提供一个安全的家。 唯一的失败模式是COM组件不支持编组。 这样做的一个缺点是每个呼叫都将被编组。 那很慢。

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