我们能解释一下STA和MTA吗?

时间:2020-03-06 14:39:44  来源:igfitidea点击:

我们能用自己的话解释STA和MTA吗?

另外,什么是单元线程,它们仅与COM有关吗?如果是这样,为什么?

解决方案

承载COM或者OLE控件的每个EXE都定义其驻留状态。默认情况下,单元状态为STA(对于大多数程序,应为STA)。

STA根据需要,所有OLE控件都必须位于STA中。 STA意味着COM对象必须始终在UI线程上进行操作,并且不能传递给其他线程(与MFC中的任何UI元素一样)。但是,程序仍然可以有许多线程。

MTA我们可以在程序中的任何线程上操作COM对象。

COM线程模型称为"公寓"模型,其中已初始化COM对象的执行上下文与单个线程(单线程单元)或者多个线程(多线程单元)相关联。在此模型中,COM对象一旦在单元中初始化,就在其运行期间成为该单元的一部分。

STA模型用于不是线程安全的COM对象。这意味着他们不处理自己的同步。这是UI组件的常见用法。因此,如果另一个线程需要与该对象进行交互(例如按表单中的按钮),则该消息将被编组到STA线程上。 Windows窗体消息泵送系统就是一个例子。

如果COM对象可以处理自己的同步,则可以使用MTA模型,其中允许多个线程与对象进行交互而无需编组调用。

STA(单线程单元)基本上是一个概念,一次只能有一个线程与代码进行交互。通过Windows消息(使用不可见的窗口)将打进公寓的电话编组起来。这样可以将呼叫排队,并等待操作完成。

MTA(多线程单元)是许多线程可以同时运行的地方,开发人员有责任处理线程安全。

关于COM中的线程模型,还有很多要学习的知识,但是如果我们在理解它们的含义时遇到困难,那么我会说了解STA是什么以及它如何工作将是最好的起点,因为大多数COM对象都是STA。

公寓线程,如果线程与其所使用的对象位于同一公寓中,则它是公寓线程。我认为这只是一个COM概念,因为它只是谈论与之交互的对象和线程的一种方式

这完全取决于如何处理对对象的调用以及它们需要多少保护。 COM对象可以要求运行时保护它们,以防止多个线程同时调用它们。那些可能无法从不同线程并发调用的线程,因此它们必须保护自己的数据。

另外,如果从用户界面线程进行调用,则运行时还必须防止COM对象调用阻塞用户界面。

公寓是存放对象的地方,它们包含一个或者多个线程。公寓定义了拨打电话时发生的情况。将在该公寓中的任何线程上接收并处理对公寓中对象的调用,但已在正确的公寓中的线程进行的调用将由其自身处理(即,直接调用该对象)。

线程可以位于单线程单元中(在这种情况下,它们是该单元中的唯一线程),也可以位于多线程单元中。它们指定线程在何时初始化该线程的COM。

STA主要是为了与绑定到特定线程的用户界面兼容。 STA通过接收到隐藏窗口的窗口消息来接收要处理的呼叫的通知;当它发出一个出站呼叫时,它将启动一个模态消息循环,以防止其他窗口消息被处理。我们可以指定要调用的消息过滤器,以便应用程序可以响应其他消息。

相比之下,所有MTA线程都为该进程共享一个MTA。如果没有可用的线程(上限为池限制),COM可能会启动一个新的工作线程来处理传入的调用。进行出站呼叫的线程只会阻塞。

为简单起见,我们将只考虑在DLL中实现的对象,这些对象通过为类的键设置ThreadingModel值在注册表中公布其支持的对象。有四个选项:

  • 主线程(不存在" ThreadingModel"值)。该对象在主机的主UI线程上创建,并且所有调用均被编组到该线程。类工厂只会在该线程上被调用。
  • 公寓。这表明该类可以在任何单线程模式线程上运行。如果创建它的线程是STA线程,则对象将在该线程上运行,否则它将在主STA中创建-如果不存在主STA,则将为其创建STA线程。 (这意味着创建Apartment对象的MTA线程将整理对另一个线程的所有调用。)类工厂可由多个STA线程并发调用,因此它必须保护其内部数据免受此攻击。
  • 免费。这表示一个旨在在MTA中运行的类。即使它是由STA线程创建的,它也将始终加载在MTA中,这再次意味着STA线程的调用将被整理。这是因为通常写" Free"对象时会期望它会阻塞。
  • 都是。这些类很灵活,可以在创建它们的任何单元中加载。但是,必须编写它们以同时满足这两组要求:必须将其内部状态防止并发调用(如果它们已装入MTA中),但不能阻塞(如果它们已装入STA中)。

在.NET Framework中,基本上只在创建UI的任何线程上使用[STAThread]。辅助线程应使用MTA,除非它们将使用带有"公寓"标记的COM组件,在这种情况下,如果从多个线程中调用同一组件,请使用STA避免编组开销和可伸缩性问题(因为每个线程都有依次等待组件)。如果每个线程使用一个单独的COM对象(无论该组件位于STA还是MTA中),这将更加容易。

我发现现有的解释也太糟糕了。这是我用普通英语的解释:

STA:
如果线程创建一个设置为STA的COM对象(调用CoCreateXXX时,我们可以传递一个将COM对象设置为STA模式的标志),则只有该线程才能访问此COM对象(这就是STA的意思是单线程单元),其他试图在此COM对象上调用方法的线程被悄悄地转变为向创建(拥有)COM对象的线程传递消息。这非常类似于只有创建UI控件的线程才能直接访问它的事实。并且该机制旨在防止复杂的锁定/解锁操作。

MTA:
如果线程创建了一个设置为MTA的COM对象,那么几乎每个线程都可以直接在其上调用方法。

这几乎是要点。尽管从技术上讲我没有提到一些细节,例如在" STA"段落中,但是创建者线程本身必须是STA。但是,这几乎是我们了解STA / MTA / NA所需要知道的全部。