定义STA:“单线程亲和力”;或者“单线公寓”;以及它们之间的关系

本文关键字:关系 之间 单线公寓 单线 STA 单线程 亲和力 定义 或者 公寓 | 更新日期: 2023-09-27 17:50:48

我正在使用WPF并且正在阅读STA的材料。两个问题:

1) STA被不同的文章定义为代表"单线程亲和"answers"单线程公寓"。前者说: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各组件使用的一种模式,线程亲和性是该模式的一个特点吗?

谢谢。

定义STA:“单线程亲和力”;或者“单线公寓”;以及它们之间的关系

STA是"单螺纹公寓"的意思。它是一个COM概念,与WPF高度无关。WPF设计者从。net 1的错误中吸取了教训。X,许多程序员编写的程序违反了线程安全要求,并且很难修复他们的程序。因此,他们在。net框架代码中添加了更多的运行时检查,以帮助他们避免麻烦。

虽然它是纯粹的COM概念,但其基本原理是相当通用的。通过声明线程STA,您可以承诺您编写的代码行为良好。通过运行调度程序循环(Application.Run)编写行为良好的代码,并且从不阻塞在线程上运行的代码。违反此承诺将导致死锁。

绝大多数。net类,以及你自己编写的大部分代码,都是线程不安全的。有两种基本方法可以使这样的代码线程安全。第一种是处理List<>类的方法,在代码中放入lock语句,以确保List对象一次只能由单个线程访问。

这通常工作得很好,但是类越复杂,就越难以确定将语句放在哪里,并且此类锁导致死锁的可能性就越大。为了保证代码线程安全,唯一的另一种选择是只在同一个线程上进行方法调用。所有的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(),即使您通常不想这样做。

STAThreadAttribute告诉。net虚拟机将初始线程的COM公寓设置为单线程公寓(STA)。

1)这就是STA的意思,A代表公寓,而不是亲和力。

这里的主要问题是在处理(外部)COM组件时,通常是GUI控件,例如实例化IE嵌入式组件的WebBrowser控件,它必须存在于STA。

2)是的,STA意味着线程亲和性,这是Win32窗口和窗口消息的要求。

在实践中,你可以用[STAThread]标记你的Main(),或者创建一个新的线程,设置它的公寓,然后启动它,只要你稍后运行一个消息循环,如Application.Run(),或WaitOneWaitHandle上,因为它将使用CoWaitForMultipleHandles

因此,以下是STAThread属性或为STA启动一个线程的含义:

  • 虚拟机将用COINIT_APARTMENTTHREADED

  • 调用CoInitializeEx
  • 你必须运行一个消息循环,以确保跨公寓调用公寓的对象

  • 即使你不期望跨公寓调用,你仍然应该运行消息循环,因为STA COM组件可能需要一个,通常是由于使用GUI api,直接或间接,例如shell函数

  • WaitOneWaitAny将使用消息泵送等待,例如CoWaitForMultipleHandles,而不是普通的WaitForSingleObjectEx/WaitForMultipleObjectsEx

  • 不支持
  • WaitAll,因为底层API将等待所有句柄消息队列,没有被动的方法来等待一组句柄消息队列

  • 的所有句柄
    STA代表"单线程公寓"——COM模型,用于处理对COM对象的多线程访问。线程亲和性是这个模型的一个暗示——一旦一个线程进入STA公寓,其他线程就不能进入这个公寓。并且不能更改公寓的线程所有者。将它们的关系描述为:单线程公寓是使用处理对COM对象的多线程访问的模型,线程亲和性是该模型的一个特征(暗示)。