【问题标题】:How will STAThread affect my multi-threaded programSTAThread 将如何影响我的多线程程序
【发布时间】:2014-08-11 17:14:03
【问题描述】:

当我尝试在 WinForm 中启动 OpenFileDialog 时,我最近在程序中遇到了与 STA 相关的错误。我已经阅读了一些内容,在将 [STAThread] 属性添加到我的主线程之前,我想知道它将如何影响我的程序的执行。
我是 COM 的外国人,所以并不是我读到的所有内容都对我有意义。让我印象深刻的几点是:

[STAThread] 属性将应用程序定义为使用单线程单元模型。 更具体地说,它将应用程序线程的状态更改为单线程。 http://www.a2zdotnet.com/View.aspx?Id=93

当一个对象被多个线程访问时,STA 体系结构可能会导致显着的性能损失。每个线程对对象的访问都是序列化的,因此每个线程必须排队等待轮到它处理对象。
http://www.codeproject.com/Articles/9190/Understanding-The-COM-Single-Threaded-Apartment-Pa

我了解线程安全的必要性,但我仍然不明白 STAThread 做了什么。在我的程序(我从另一个开发人员那里继承)中,主线程启动了其他几个线程,其中一个线程初始化了 UI 表单——我认为这就是问题所在。随着[STAThread] 添加了新线程会发生什么?这会影响非 Windows 对象的多线程通信吗?

当我尝试在我的一个表单中打开OpenFileDialog 时发生错误。我使用 VS 设计器将对话框添加到表单中:它不起作用。然后我尝试在由主线程运行的全局文件中创建一个对话框,并从我的表单中调用该实例。没有效果。

【问题讨论】:

  • This StackOverflow question 解释的很清楚。
  • @icemanind 我很惊讶当我输入自己的问题时,这不是一个建议的问题。这是一个很好的解释,但没有解释其他衍生线程会发生什么(如果有的话)。
  • @ChristopheD 我的错误消息是Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process。我不明白为什么我无法从创建它的表单中调用该对话框。
  • 该属性用于指示此线程是单单元线程。这用于 COM 互操作,某些控件需要它来提供其功能

标签: c# multithreading com sta


【解决方案1】:

[STAThread] 或 Thread.SetApartmentState() 非常非常重要。您向操作系统做出承诺,您将编写行为良好的代码。它对 Windows 中的大量代码以及您使用的非线程安全组件很重要。此类代码的标准示例包括剪贴板、拖放、shell 对话框(如 OpenFileDialog)、WebBrowser 等组件以及许多由 .NET 类包装的 Windows 子组件。

线程安全总是很重要,编写真正线程安全的代码非常非常困难。 .NET Framework 本身很少完成它。非常基本的类列表 List 不是线程安全的。

通过使 promise 表现良好,您必须遵守在报告自己为 STA 线程的线程中编写代码的规则。你必须做两件基本的事情:

  1. 您必须抽取消息循环。在 Winforms 或 WPF 应用程序中又称为 Application.Run()。消息循环是一种基本机制,您可以通过它让代码在特定线程上运行。它是producer-consumer problem 的通用解决方案。这解决了线程安全问题,如果你总是从同一个线程调用线程不安全代码,那么它就不再不安全了。

  2. 您绝不能阻塞您的线程。阻塞 STA 线程非常可能导致死锁。因为它阻止了那些不是线程安全的代码块被调用。 CLR 中对此有核心支持,使用 WaitOne() 阻塞 STA 线程会导致它自己泵送消息循环。

在 Winforms 或 WPF 应用程序中很容易满足这些要求。它们是完全设计用于帮助您实现它们的类库。几乎他们行为方式的每一个方面都受到了它的影响。

必须将 GUI 应用程序中的 Main() 方法标记为 [STAThread]。创建窗口时的严格要求。

支持并且可以创建另一个显示窗口的线程。这次必须调用 SetApartmentState() 切换到 STA,它不能是线程池线程。做到这一点非常困难,在 Winforms 中,如果您使用某些类型的控件,您将被 SystemEvents 类严重咬伤。它有开始在错误的线程上引发事件的诀窍。调试这样的问题需要look like this 的黑带技能。估计会吓到你。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    • 2018-03-14
    • 2023-03-18
    • 1970-01-01
    • 2013-05-25
    相关资源
    最近更新 更多