定义 STA:"single thread affinity" 或 "single threaded apartment";以及它们之间的关系
Defining STA: "single thread affinity" or "single threaded apartment"; and how they relate
我正在使用 WPF 并正在阅读 STA 上的资料。两个问题:
1) STA被不同的文章定义为代表"single thread affinity"和"single threaded apartment"。
这说前者:
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 表示 "Single Threaded Apartment"。它是一个 COM 概念,与 WPF 高度无关。 WPF 设计者从 .NET 1.x 中的错误中吸取了教训,许多程序员编写的程序违反了线程安全要求并且很难修复他们的程序。因此,他们在 .NET 框架代码中添加了更多运行时检查,以帮助他们远离麻烦。
虽然它是纯 COM 概念,但其基本原理非常通用。通过声明线程 STA,您可以承诺您编写的代码是行为良好的。您通过 运行 调度程序循环 (Application.Run) 编写行为良好的代码,并且永远不会阻塞在线程上运行的代码。违背这个承诺会导致僵局。
绝大多数 .NET classes 以及您自己编写的大部分代码都是线程不安全的。有两种基本方法可以使此类代码线程安全。第一个是你对像 List<> 这样的 class 采取的方法,你在代码中放置 lock 语句以确保 List 对象只能由单个一次线程。
这通常可以正常工作,但是 class 越复杂,就越难弄清楚 lock 语句的放置位置,几率就越高这样的锁会导致死锁。保持代码线程安全的唯一其他选择是只在同一线程上进行方法调用。所有 WPF 组件都是这样,您必须 从工作线程调用 Dispatcher.Begin/Invoke() 来设置它们的属性或调用它们的方法。您现在可以说该对象具有线程亲和性,它只能在创建它的线程中使用。
WPF 设计者想要添加这些运行时检查以告诉程序员他使用的 WPF 组件有误。该组件只能在调用 Application.Run() 的线程上工作,这样 Dispatcher.Begin/Invoke() 才能工作。问题是,他们无法判断线程是否要调用 Application.Run()。这经常发生在以后。需要一个承诺。
所以他们借用了 COM 的承诺,线程的单元状态总是被设置并给出了一个体面的提示它将如何表现。没有保证,只是一个体面的提示。 WPF 应用程序的主线程几乎总是合适的,由于 Main() 入口点上的 [STAThread] 属性,它是 STA,项目模板确保它调用 Application.Run()。任务或线程池线程位于 MTA 中,永远不会调用 Application.Run(),因此对于 WPF 组件来说这是一个非常不利的地方。
它们产生的异常使程序员远离麻烦。请注意如何可以非常轻松地抑制此异常。您所要做的就是调用 Thread.SetApartmentState() 来做出承诺。但是当然你现在是在没有安全网的情况下飞行,WPF 不能再告诉你你做错了,现在完全取决于你是否正确编写代码。您必须调用 Application.Run(),即使您通常不想这样做。
STAThreadAttribute
告诉 .NET 虚拟机将初始线程的 COM 单元设置为单线程单元 (STA)。
1)这是STA的意思,A是apartment,不是affinity
这里的主要问题是在处理(外部)COM 组件时,通常是 GUI 控件,例如实例化 IE 的嵌入式组件的 WebBrowser
控件,它必须存在于 STA 中。
2) 是的,STA 意味着线程亲和性,这通常是 Win32 windows 和 window 消息的要求。
实际上,您可以用 [STAThread]
标记您的 Main()
或创建一个新线程 set its apartment and then start it, as long as you run a message loop later on, such as Application.Run()
, or WaitOne
on a WaitHandle
, since it'll use CoWaitForMultipleHandles
。
因此,这里是 STAThread
属性或启动为 STA 设置的线程的含义:
虚拟机会用COINIT_APARTMENTTHREADED
调用CoInitializeEx
你必须运行一个消息循环来确保跨公寓调用公寓的对象
即使您不期望跨公寓调用,您仍然应该运行一个消息循环,因为 STA COM 组件可能需要一个,通常是由于使用 GUI APIs,直接或间接,例如shell 函数
WaitOne
和 WaitAny
将使用消息推送等待,例如 CoWaitForMultipleHandles
而不是普通的 WaitForSingleObjectEx
/WaitForMultipleObjectsEx
不支持WaitAll
,因为底层API会等待所有句柄和消息队列,没有被动等待一组句柄的所有句柄的方法或消息队列
- STA 代表 "single threaded apartment" - 用于处理对 COM 对象的多线程访问的 COM 模型。线程亲和性是这个模型的一个含义——一旦一个线程进入 STA 单元,其他线程就不能进入这个单元。公寓的线程所有者不能更改。
- 将它们的关系描述为是正确的:单线程单元是一种模型,用于处理对 COM 对象的多线程访问,线程亲和性是一个特征(该模型的含义)。
我正在使用 WPF 并正在阅读 STA 上的资料。两个问题:
1) STA被不同的文章定义为代表"single thread affinity"和"single threaded apartment"。 这说前者: 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 表示 "Single Threaded Apartment"。它是一个 COM 概念,与 WPF 高度无关。 WPF 设计者从 .NET 1.x 中的错误中吸取了教训,许多程序员编写的程序违反了线程安全要求并且很难修复他们的程序。因此,他们在 .NET 框架代码中添加了更多运行时检查,以帮助他们远离麻烦。
虽然它是纯 COM 概念,但其基本原理非常通用。通过声明线程 STA,您可以承诺您编写的代码是行为良好的。您通过 运行 调度程序循环 (Application.Run) 编写行为良好的代码,并且永远不会阻塞在线程上运行的代码。违背这个承诺会导致僵局。
绝大多数 .NET classes 以及您自己编写的大部分代码都是线程不安全的。有两种基本方法可以使此类代码线程安全。第一个是你对像 List<> 这样的 class 采取的方法,你在代码中放置 lock 语句以确保 List 对象只能由单个一次线程。
这通常可以正常工作,但是 class 越复杂,就越难弄清楚 lock 语句的放置位置,几率就越高这样的锁会导致死锁。保持代码线程安全的唯一其他选择是只在同一线程上进行方法调用。所有 WPF 组件都是这样,您必须 从工作线程调用 Dispatcher.Begin/Invoke() 来设置它们的属性或调用它们的方法。您现在可以说该对象具有线程亲和性,它只能在创建它的线程中使用。
WPF 设计者想要添加这些运行时检查以告诉程序员他使用的 WPF 组件有误。该组件只能在调用 Application.Run() 的线程上工作,这样 Dispatcher.Begin/Invoke() 才能工作。问题是,他们无法判断线程是否要调用 Application.Run()。这经常发生在以后。需要一个承诺。
所以他们借用了 COM 的承诺,线程的单元状态总是被设置并给出了一个体面的提示它将如何表现。没有保证,只是一个体面的提示。 WPF 应用程序的主线程几乎总是合适的,由于 Main() 入口点上的 [STAThread] 属性,它是 STA,项目模板确保它调用 Application.Run()。任务或线程池线程位于 MTA 中,永远不会调用 Application.Run(),因此对于 WPF 组件来说这是一个非常不利的地方。
它们产生的异常使程序员远离麻烦。请注意如何可以非常轻松地抑制此异常。您所要做的就是调用 Thread.SetApartmentState() 来做出承诺。但是当然你现在是在没有安全网的情况下飞行,WPF 不能再告诉你你做错了,现在完全取决于你是否正确编写代码。您必须调用 Application.Run(),即使您通常不想这样做。
STAThreadAttribute
告诉 .NET 虚拟机将初始线程的 COM 单元设置为单线程单元 (STA)。
1)这是STA的意思,A是apartment,不是affinity
这里的主要问题是在处理(外部)COM 组件时,通常是 GUI 控件,例如实例化 IE 的嵌入式组件的 WebBrowser
控件,它必须存在于 STA 中。
2) 是的,STA 意味着线程亲和性,这通常是 Win32 windows 和 window 消息的要求。
实际上,您可以用 [STAThread]
标记您的 Main()
或创建一个新线程 set its apartment and then start it, as long as you run a message loop later on, such as Application.Run()
, or WaitOne
on a WaitHandle
, since it'll use CoWaitForMultipleHandles
。
因此,这里是 STAThread
属性或启动为 STA 设置的线程的含义:
虚拟机会用
COINIT_APARTMENTTHREADED
调用你必须运行一个消息循环来确保跨公寓调用公寓的对象
即使您不期望跨公寓调用,您仍然应该运行一个消息循环,因为 STA COM 组件可能需要一个,通常是由于使用 GUI APIs,直接或间接,例如shell 函数
WaitOne
和WaitAny
将使用消息推送等待,例如CoWaitForMultipleHandles
而不是普通的WaitForSingleObjectEx
/WaitForMultipleObjectsEx
不支持WaitAll
,因为底层API会等待所有句柄和消息队列,没有被动等待一组句柄的所有句柄的方法或消息队列
CoInitializeEx
- STA 代表 "single threaded apartment" - 用于处理对 COM 对象的多线程访问的 COM 模型。线程亲和性是这个模型的一个含义——一旦一个线程进入 STA 单元,其他线程就不能进入这个单元。公寓的线程所有者不能更改。
- 将它们的关系描述为是正确的:单线程单元是一种模型,用于处理对 COM 对象的多线程访问,线程亲和性是一个特征(该模型的含义)。