我正在学习多线程概念(通常针对C#.NET)。阅读不同的文章,仍然无法完全理解一些基本概念。

我发布this问题。 “汉斯·帕桑特”(Hans Passant)很好地解释了这一点,但我无法理解其中的一部分。所以我开始谷歌搜索。

我读了this问题,没有答案。

多线程和MTA是否相同?

假设我编写了一个STA的WinForm应用程序(如上所述,它的Main()方法),但仍然可以在我的应用程序中创建多个线程。我可以肯定地说我的应用程序是“多线程的”。这是否也意味着我的应用程序是MTA?

在谈论STA/MTA时,大多数文章(例如this)都在谈论COM/DCOM/Automation/ActiveX。这是否意味着DotNet与STA/MTA无关?

最佳答案

不能。MTA与STA一样,是单线程的属性。现在,您做出完全相反的 promise ,您声明该线程绝对不执行任何操作来保持外部代码的线程安全。因此,无需 dispatch 人员,您就可以根据需要阻止任意数量的内容。

当然,这会带来后果,并且可能会令人非常不快。如果程序的UI线程位于MTA中,则将是致命的,因为它使用了许多根本上是线程不安全的外部组件。剪贴板不起作用,拖放操作不起作用,OpenFileDialog通常只是挂起您的程序,WebBrowser不会触发其事件。

一些组件会对此进行检查并引发异常,但是这种检查并没有始终如一地实现。 WPF是值得注意的,而单元状态通常仅对非托管代码重要,WPF借用了该概念并提出“调用线程必须是STA,因为许多UI组件都需要STA。”这有点误导,实际上意味着线程必须具有一个调度程序才能允许其控件工作。但是在其他方面与STA的 promise 一致。

当组件使用COM且作者提供了代理时,它可以工作。 COM基础结构现在介入以使组件成为线程安全的,它创建了一个新线程STA,以为其提供安全的家。而且,每个方法调用都会自动编码(marshal),以便在该线程上运行,从而提供线程安全性。与Dispatcher.Invoke()完全等效,但完全是自动完成的。然而,结果是这很慢,通常需要几纳秒的简单属性访问现在可能需要数微秒。

如果该组件同时支持MTA和STA,您将很幸运。这是不常见的,只有像Microsoft这样的人才能花更多的时间才能保持其库的线程安全性。

我也许应该强调,.NET Framework中完全没有公寓的概念。除了说明单元类型的基础知识以外,这是必需的,因为.NET程序通常需要与非托管代码互操作。因此,使用工作线程编写Winforms应用程序就可以了,并且那些工作线程始终位于MTA中,但是您确实需要自己处理线程安全问题,并且没有自动的方法。

通常这是很容易理解的,几乎每个人都知道如何使用lock关键字,Task和Background类,并且知道需要使用Control.Begin/Invoke()方法从工作线程更新UI。使用InvalidOperationException可以在错误时提醒您。由程序员而不是由系统负责线程安全的问题确实使使用线程变得更加困难。但是给您提供了很多比系统更好地做它的机会。必要的是,在90年代后期的中间件 war 期间,当Java将其猛击时,这种系统提供的线程安全性遭到了严重的关注。

10-06 11:00