c# - 定义 STA : "single thread affinity" or "single threaded apartment"; and how they relate

标签 c# wpf winforms com sta

我正在使用 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 各种组件使用的模型,线程亲和性是该模型的特征?

谢谢。

最佳答案

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

虽然它是纯 COM 概念,但其基本原理非常通用。通过声明一个线程 STA,您可以 promise 您编写的代码是行为良好的。您可以通过运行调度程序循环 (Application.Run) 来编写行为良好的代码,并且永远不会阻塞在线程上运行的代码。违背这个 promise 会导致僵局。

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

这通常可以正常工作,但是类越复杂,就越难找出放置 lock 语句的位置,并且此类锁导致死锁的可能性就越高。保持代码线程安全的唯一其他选择是只在同一线程上进行方法调用。所有 WPF 组件都是这样,您必须从工作线程调用 Dispatcher.Begin/Invoke() 来设置它们的属性或调用它们的方法。您现在可以说该对象具有线程亲和性,它只能在创建它的线程中使用。

WPF 设计者想要添加这些运行时检查以告诉程序员他使用的 WPF 组件有误。该组件只能在调用 Application.Run() 的线程上工作,这样 Dispatcher.Begin/Invoke() 才能工作。问题是,他们无法判断线程是否要调用 Application.Run()。这经常发生在以后。需要一个 promise 。

所以他们借用了 COM 的 promise ,线程的单元状态总是被设置并给出一个体面的提示它将如何表现。没有保证,只是一个体面的提示。 WPF 应用程序的主线程几乎总是合适的,由于 Main() 入口点上的 [STAThread] 属性,它是 STA,项目模板确保它调用 Application.Run()。任务或线程池线程位于 MTA 中,永远不会调用 Application.Run(),因此对于 WPF 组件来说这是一个非常不利的地方。

它们产生的异常使程序员远离麻烦。请注意如何可以非常轻松地抑制此异常。您所要做的就是调用 Thread.SetApartmentState() 来做出 promise 。但是当然你现在是在没有安全网的情况下飞行,WPF 不能再告诉你你做错了,现在完全取决于你是否正确编写代码。您必须调用 Application.Run(),即使您通常不想这样做。

关于c# - 定义 STA : "single thread affinity" or "single threaded apartment"; and how they relate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30454218/

相关文章:

c# - 在 Windows 窗体应用程序中使用 CaSTLe Windsor

c# - 执行异步 lambda 的等待 Task.Run 的一个好的替代方案是什么?

c# - 如何自动刷新excel公式?

c# - PresentationFramework.dll 中出现类型为 'System.Windows.Markup.XamlParseException' 的未处理异常

c# - BindingError 会降低应用程序性能吗?

wpf - InputBindings 仅在聚焦时才起作用

c# - Windows窗体中的Panel和ScrollBar

c# - 在c#中移动文件而不重命名

c# - 更改 C# 中的编码?

c# - 作为泛型类型传递的访问类属性