ApartmentState for dummies

Ben*_*jol 111 .net multithreading

我刚用这个纠正了一个bug:

_Thread.SetApartmentState(ApartmentState.STA);
Run Code Online (Sandbox Code Playgroud)

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

Han*_*ant 219

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

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

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

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

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

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

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

我之前提供了一个答案,其中包含有关保持COM快乐的消息循环的重要性的更多详细信息.你会在这里找到这篇文章.

  • 很好的答案!我解决的错误是我为一个长期运行的报表生成器创建的一个线程,它使用WPF控件来构建报表的一部分,所以这是有意义的,虽然我不知道该线程上有一个消息循环. (3认同)
  • 我非常认真地阅读MSDN帖子几次才能理解它,你的答案非常清晰,写得很好.谢谢! (2认同)