我正在与WPF合作,正在阅读STA上的资料。两个问题:
1)STA被定义为代表"单线程亲和力"和"单线程公寓"通过不同的文章。 这说前者: https://msdn.microsoft.com/en-us/library/ms750441(v=vs.110).aspx 这说明后者: https://msdn.microsoft.com/en-us/library/ms742522(v=vs.110).aspx
这是什么,或者STA可以参考这些相关概念中的任何一个?
2)将他们的关系描述为: 单线程单元是Windows各种组件使用的模型,线程亲和性是该模型的一个特征吗?
感谢。
答案 0 :(得分:11)
虽然它是纯粹的COM概念,但其基本原则非常普遍。通过声明一个线程STA,您可以使 promise 表明您编写的代码表现良好。您通过运行调度程序循环(Application.Run)编写行为良好的代码,并且永远不会阻止在该线程上运行的代码。打破这一承诺会导致僵局。
绝大多数.NET类以及您自己编写的大多数代码都是线程不安全的。有两种基本方法可以使这些代码具有线程安全性。第一个是您使用List<>这样的类的方法,您在代码中放置了 lock 语句,以确保List对象一次只能被一个线程访问。 / p>
这通常可以正常工作,但是类越精细,就越难弄清楚 lock 语句的放置位置以及这种锁导致死锁的几率越高。然后,您必须保持代码线程安全的唯一其他选项是仅在同一线程上进行方法调用。所有的WPF组件都是这样的,你必须从工作线程调用Dispatcher.Begin / Invoke()来设置它们的属性或调用它们的方法。您现在可以说该对象具有线程关联性,它只能从创建它的线程中使用。
WPF设计人员希望添加这些运行时检查,以告诉程序员他使用的WPF组件是错误的。该组件只能在调用Application.Run()的线程上工作,以便Dispatcher.Begin / Invoke()能够工作。问题是,他们无法判断该线程是否将调用Application.Run()。这经常发生在以后。需要承诺。
因此,他们借用了COM承诺,线程的公寓状态始终设置并提供了一个体面的提示它将如何表现。不能保证,只是一个不错的提示。 WPF应用程序的主线程几乎总是合适的,它是STA,这要归功于Main()入口点上的[STAThread]属性,项目模板确保它调用Application.Run()。并且任务或线程池线程在MTA中,并且永远不会调用Application.Run(),因此对于WPF组件来说是一个非常恶劣的地方。
它们产生的异常使程序员免于麻烦。请注意如何轻松地抑制此异常。您所要做的就是调用Thread.SetApartmentState()来做出承诺。但是当然你现在没有安全网飞行,WPF再也不能告诉你你做错了,现在完全由你来正确编写代码。您必须调用Application.Run(),即使您通常不希望这样做。
答案 1 :(得分:2)
STAThreadAttribute
告诉.NET虚拟机将初始线程的COM单元设置为Single-Threaded Apartment(STA)。
1)这就是STA的意思,A代表公寓,而非亲和力。
这里的主要问题是处理(外部)COM组件时,通常是GUI控件,例如实例化IE嵌入式组件的WebBrowser
控件,该控件必须存在于STA中。
2)是的,STA意味着线程亲和性,这通常是Win32窗口和窗口消息的要求。
实际上,您可以使用Main()
标记[STAThread]
或创建新主题set its apartment,然后启动它,只要您稍后运行消息循环,例如Application.Run()
上的WaitOne
或WaitHandle
,因为它会使用CoWaitForMultipleHandles
。
因此,以下是STAThread
属性的含义或启动为STA设置的线程:
虚拟机将使用CoInitializeEx
COINIT_APARTMENTTHREADED
您必须运行消息循环以确保对公寓对象的跨公寓调用
即使您不期望跨公寓呼叫,您仍应运行消息循环,因为STA COM组件可能需要一个,通常是由于使用GUI API,直接或间接,例如shell函数
WaitOne
和WaitAny
将使用消息抽取等待,例如CoWaitForMultipleHandles
而非普通WaitForSingleObjectEx
/ WaitForMultipleObjectsEx
WaitAll
不受支持,因为底层API会等待所有句柄和消息队列,没有被动方式等待一组句柄的所有句柄消息队列或
答案 2 :(得分:2)