STAThread和多线程


102

从STAThread上的MSDN文章中:

指示应用程序的COM线程模型是单线程单元(STA)。

(供参考,这是整篇文章。)

单线程公寓...好吧,这让我头疼。另外,我在某处读到,除非您的应用程序使用COM互操作,否则此属性实际上什么都不做。那么它到底是做什么的,又如何影响多线程应用程序呢?Timer即使“为了安全”,多线程应用程序(包括使用s的任何人到异步方法调用,而不仅仅是线程池之类的东西)都应该使用MTAThread吗?STAThread和MTAThread实际做什么?

Answers:


60

单元线程是COM概念。如果您不使用COM,并且您调用的所有API都不在“幕后”使用COM,那么您就不必担心公寓。

如果您确实需要注意公寓,那么细节可能会有些复杂;一个可能过于简化的版本是,标记为STA的COM对象必须在STAThread上运行,标记为MTA的COM对象必须在MTA线程上运行。使用这些规则,COM可以优化这些不同对象之间的调用,从而避免在不必要的地方进行封送处理。


7
这太简单了。多线程对象可以在任何线程中运行。公寓线程对象只能以其在创建公寓运行。
1800信息

28
从STA线程上的STA对象到MTA对象的调用将封送至MTA线程(除非MTA对象实现了自由线程封送处理程序)。就像我说的,细节可能会变得复杂。(我在COM团队工作了很多年咧着嘴笑
布鲁斯

9
有时,即使您不直接使用COM,也需要意识到这一点。如果线程显示任何图形窗口,则必须使用“单线程单元”模型。这就是[STAThread]总是显示在Windows窗体应用程序的main方法顶部的原因。
贾斯汀·埃斯蒂尔2009年

6
在您不知情的情况下,诸如“字体”或“文件”对话框之类的东西无法使用COM吗?我假设它们在内部完成,这是否意味着几乎所有Windows Forms应用程序都需要设置STAThread?原谅我的天真的假设,因为我实际上还没有完成COM编程。
Brett Ryan


3

它所做的是确保CoInitialize将COINIT_APARTMENTTHREADED指定为参数被调用。如果您不使用任何COM组件或ActiveX控件,则对您完全没有影响。如果您这样做,那将很关键。

单元线程的控件实际上是单线程的,对它们的调用只能在创建它们的单元中处理。

来自MSDN的更多详细信息:

在单线程单元(STA)中创建的对象仅从其单元的线程接收方法调用,因此调用被序列化,并且仅到达消息队列边界(调用Win32函数PeekMessage或SendMessage时)。

在多线程单元(MTA)的COM线程上创建的对象必须能够随时接收来自其他线程的方法调用。通常,您将使用Win32同步原语(例如关键部分,信号量或互斥体)在多线程对象的代码中实现某种形式的并发控制,以帮助保护对象的数据。

当被配置为在中性线程单元(NTA)中运行的对象被STA或MTA中的线程调用时,该线程将转移到NTA。如果此线程随后调用CoInitializeEx,则调用将失败并返回RPC_E_CHANGED_MODE。


从COM角度来看,MSDN文章很有帮助,但是您可以告诉我.NET何时调用CoInitialize()以响应STAThread属性/ ApartmentState吗?注意:有关MSDN的文章在这里:CoInitializeEx函数
jrh

thread-> SetApartment是否在CoInitialize()内部使用?我一直跟踪STAThread属性,但是踪迹变得很冷(我找不到的来源Thread::SetApartment)。是否在任何地方记录了thread.h(COM thread.h)中的Thread类?是MFC,ATL还是其他?
jrh

@jrh除了这样的遗憾,我不知道更多细节
1800年信息

-15

STAThread是在C#GUI项目的Main函数之前编写的。它什么都不做,但是允许程序创建一个线程。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.