ApartmentState for dummies

时间:2010-11-11 12:34:49

标签: .net multithreading

我刚用这个纠正了一个错误:

_Thread.SetApartmentState(ApartmentState.STA);

现在我想了解它的含义,以及它的工作原理!

1 个答案:

答案 0 :(得分:204)

COM是.NET的盛大之父。他们有很高的目标,COM所做的事情之一,但.NET完全跳过为一个类提供线程保证。 COM类可以发布它具有的线程要求。 COM基础设施可确保满足这些要求。

这在.NET中完全不存在。您可以使用队列<>例如,在多个线程中对象,但如果你没有正确锁定,你的代码中就会有一个很难诊断的错误。

COM线程的确切细节太大,无法放入帖子中。我将专注于你的问题的具体细节。创建COM对象的线程必须告诉COM它希望为具有受限制的线程选项的COM类提供什么样的支持。绝大多数类只支持所谓的Apartment线程,它们的接口方法只能从创建实例的同一线程中安全地调用。换句话说,他们宣布“我不支持任何线程,请注意从不从错误的线程中调用我”。即使客户端代码实际 从另一个线程调用它。

有两种,STA(单线程公寓)和MTA。它在CoInitializeEx()调用中指定,该函数必须由任何与COM执行任何操作的线程调用。 CLR在启动线程时自动调用该调用。对于程序的主启动线程,它从Main()方法的[STAThread]或[MTAThread]属性获取值。默认为MTA。对于您自己创建的线程,它由您对SetApartmentState()的调用决定。默认为MTA。线程池线程始终是MTA,无法更改。

Windows中有很多代码需要STA。值得注意的例子是Clipboard,Drag + Drop和shell对话框(如OpenFileDialog)。 WPF或Windows窗体项目的UI线程应始终为STA,与创建窗口的任何线程一样。

你对COM做出的承诺,你的线程是STA,但确实要求你遵循单线程公寓合同。他们非常僵硬,当你违反合同时,你很难确定麻烦。要求是您从不在任何时间内阻止线程并且您需要抽取消息循环。后一个要求由WPF或Winforms的UI线程满足,但如果您创建自己的STA线程,则需要自己处理。违反合同的常见诊断是僵局。

CLR内置了相当多的支持来支持这些要求btw,帮助您避免麻烦。例如, lock 语句将在STA线程上阻塞时引发消息循环。大多数同步类也可以,Mutex是一个值得注意的例外。但是,这只需要处理 never-block 要求,您仍然需要创建自己的消息循环。 WPF和Winforms中的Application.Run()。

我之前提供了一个答案,其中包含有关保持COM满意的消息循环的重要性的更多详细信息。你会找到post here