线程公寓州

时间:2011-03-02 14:26:11

标签: c# multithreading

全部,

我一直在C#中使用线程一段时间,但我仍然对线程的公寓状态的真正含义感到困惑。我知道WinForms必须始终使用STA公寓状态(而不是MTA),但我仍然不清楚公寓状态是什么。

2 个答案:

答案 0 :(得分:9)

COM有很高的目标。其中之一是线程是一个非常难以正确编程的编程细节,应由支持库管理。与.NET非常不同的是,完全由您来使用以线程安全方式不是线程安全的类。

这通过注册表工作,COM coclass发布ThreadingModel注册表项,说明它支持哪种类型的线程。到目前为止,大多数人都使用“公寓”,这是一种有点不明确的说法“我不支持多线程”。这是COM的一个信号,以确保以线程安全的方式调用所有方法。如果程序从工作线程调用方法,那么COM负责将来自worker的调用封送到创建实例的线程。因此,自动确保以线程安全的方式使用服务器。与Control.Invoke和Dispatcher.Invoke的工作方式不同,但完全自动。

这当然是一种奇妙的魔力,但你的程序确实需要合作一点。如果没有你的帮助,COM无法组织这样的电话。当您的程序创建一个线程时,它必须调用CoInitialize()来告诉COM基础结构您要参与COM调用。那时,您必须告诉它您创建的线程的。有两种,以“公寓”类型为特色。有STA(单线程公寓)和MTA(多个)。 STA线程是不支持线程的COM组件的好客主页。 MTA线程不是。

虽然这种公寓附有价格标签。创建STA时,您必须遵循STA规则。这有点夸张:

  • 必须抽取Windows消息循环
  • 永远不会阻止线程

消息循环是COM将一个线程调用到另一个线程的机制。永不阻止规则是防止死锁所必需的。虽然是严苛的,但它是程序的UI线程的工作方式。这不是巧合。

还有一个价格标签附加在MTA线程上创建公寓线程COM对象。这样的线程是一个好的家,它不遵循STA规则。 COM无法提供帮助,并且可以调整方法调用。 COM介入并实际创建自己的STA线程,为对象提供一个好客的家。很好,但便宜,因为它会烧掉一个线程并且每个方法调用都被封送,这会给每次调用增加很多开销。

COM线程支持相当不错,它可以在98%的时间内处理所有事情而无需做任何特殊操作。然而,2%可以给你一个巨大的偏头痛,你可以做很少的事情来打击它。它的扩展性也非常差,可能是.NET没有任何相似之处的最大原因。

虽然COM似乎已经死了,但公寓在Windows编程中仍然是一个非常大的问题。 .NET框架明确支持它们。例如,在STA线程上调用Thread.Join()或Monitor.Enter(),由COM显式禁止,使CLR泵成为消息循环。其他工件是您在GUI应用程序的Main()方法和Thread.SetApartmentState()上看到的[STAThread]属性,这是获取CLR调用CoInitialize()的正确方法。剪贴板,拖放和shell对话框(如OpenFileDialog)等GUI功能明确要求STA工作。创建任何窗口的线程应始终是STA线程。

答案 1 :(得分:2)

这篇由Raymond Chen撰写的关于The Old New Thing的博客文章介绍了STA和MTA线程模型背后的一些历史:

  

User interface code + multi-threaded apartment = death

     

[。 。 。 COM成长了两个人,一个   专注于GUI客户和   另一个侧重于非GUI   顾客。对于非GUI客户,   附加功能,如   多线程公寓被添加,   而且由于客户没有做GUI   东西,多线程公寓   不受GUI规则的影响。   他们没有发布消息   相互沟通;他们用   内核对象和   WaitForSingleObject的。每个人都赢了,   正确?

     

嗯,是的,每个人都赢了,但是你   必须知道你的面包是哪一面   涂上黄油。如果您初始化GUI   线程作为多线程公寓,   你违反了这些假设   在哪个多线程公寓   被发明了! [。 。 。 ]