Answers:
COM线程模型称为“公寓”模型,其中已初始化COM对象的执行上下文与单个线程(单线程单元)或多个线程(多线程单元)相关联。在此模型中,COM对象一旦在单元中初始化,就在其运行期间成为该单元的一部分。
STA模型用于不是线程安全的COM对象。这意味着他们不处理自己的同步。这是UI组件的常见用法。因此,如果另一个线程需要与该对象进行交互(例如按表单中的按钮),则该消息将被编组到STA线程上。Windows窗体消息泵送系统就是一个例子。
如果COM对象可以处理自己的同步,则可以使用MTA模型,其中允许多个线程与对象进行交互而无需编组调用。
这完全取决于如何处理对对象的调用以及它们需要多少保护。COM对象可以要求运行时保护它们,以防止多个线程同时调用它们。那些可能无法从不同线程并发调用的线程,因此它们必须保护自己的数据。
另外,如果从用户界面线程进行了调用,则运行时还必须防止COM对象调用阻塞用户界面。
一个公寓是对象住的地方,它们包含一个或多个线程。公寓定义了拨打电话时发生的情况。将在该公寓中的任何线程上接收并处理对公寓中对象的调用,但由本身已处理正确的公寓中的线程进行的调用(即,直接调用该对象)除外。
线程可以位于单线程单元中(在这种情况下,它们是该单元中的唯一线程),也可以位于多线程单元中。它们指定线程在何时初始化该线程的COM。
STA主要是为了与绑定到特定线程的用户界面兼容。STA通过接收到隐藏窗口的窗口消息来接收处理呼叫的通知;当它进行出站呼叫时,它将启动一个模式消息循环,以防止其他窗口消息被处理。您可以指定要调用的消息过滤器,以便您的应用程序可以响应其他消息。
相比之下,所有MTA线程都为该进程共享一个MTA。如果没有可用的线程(上限为池限制),COM可能会启动一个新的工作线程来处理传入的调用。进行出站呼叫的线程只会阻塞。
为简单起见,我们将仅考虑在DLL中实现的对象,这些对象通过设置ThreadingModel
类的键的值在注册表中公布其支持的内容。有四个选项:
ThreadingModel
值不存在)。该对象是在主机的主UI线程上创建的,所有调用均被编组到该线程。类工厂只会在该线程上被调用。Apartment
。这表明该类可以在任何单线程模式线程上运行。如果创建它的线程是STA线程,则该对象将在该线程上运行,否则它将在主STA中创建-如果不存在主STA,则将为其创建STA线程。(这意味着创建Apartment对象的MTA线程将整理对另一个线程的所有调用。)类工厂可以由多个STA线程并发调用,因此它必须防止其内部数据受到攻击。Free
。这表示一个旨在在MTA中运行的类。即使由STA线程创建,它将始终加载到MTA中,这再次意味着STA线程的调用将被整理。这是因为Free
通常在编写对象时会期望它会阻塞。Both
。这些类很灵活,可以在创建它们的任何单元中加载。但是,必须编写它们以同时满足这两组要求:必须将其内部状态防止并发调用(如果它们已装入MTA中),但不能阻塞(如果它们已装入STA中)。从.NET Framework开始,基本上只[STAThread]
在创建UI的任何线程上使用。辅助线程应使用MTA,除非它们将使用Apartment
带有标记的COM组件,在这种情况下,如果从多个线程中调用同一组件,请使用STA避免编组开销和可伸缩性问题(因为每个线程都必须等待组件)。如果每个线程使用一个单独的COM对象(无论该组件位于STA还是MTA中),这将更加容易。
我发现现有的解释也太糟糕了。这是我用普通英语的解释:
STA:如果线程创建一个设置为STA的COM对象(调用CoCreateXXX时,您可以传递一个将COM对象设置为STA模式的标志),那么只有该线程可以访问此COM对象(这就是STA的含义-单线程公寓),试图在此COM对象上调用方法的其他线程在后台被悄悄转变为向创建(拥有)COM对象的线程传递消息。这非常类似于只有创建UI控件的线程才能直接访问它的事实。并且该机制旨在防止复杂的锁定/解锁操作。
MTA:如果线程创建了一个设置为MTA的COM对象,那么几乎每个线程都可以直接在其上调用方法。
这几乎是要点。尽管从技术上讲我没有提到一些细节,例如在“ STA”段落中,但是创建者线程本身必须是STA。但是,这几乎是您了解STA / MTA / NA所需要知道的全部。
STA(单线程单元)基本上是一个概念,一次只能有一个线程与您的代码进行交互。通过Windows消息(使用不可见的窗口)将打进公寓的电话编组起来。这样可以将呼叫排队,并等待操作完成。
MTA(多线程单元)是许多线程可以同时运行的地方,开发人员有责任处理线程安全。
关于COM中的线程模型,还有很多要学习的知识,但是如果您在理解它们的含义时遇到困难,那么我会说了解STA是什么以及它如何工作将是最好的起点,因为大多数COM对象都是STA的。
公寓线程,如果线程与其所使用的对象位于同一公寓中,则它是公寓线程。我认为这只是一个COM概念,因为它只是谈论与之交互的对象和线程的一种方式。
承载COM或OLE控件的每个EXE都定义其驻留状态。默认情况下,单元状态为STA(对于大多数程序,应为STA)。
STA-根据需要,所有OLE控件都必须位于STA中。STA意味着您的COM对象必须始终在UI线程上进行操作,并且不能传递给其他线程(与MFC中的任何UI元素一样)。但是,您的程序仍然可以有许多线程。
MTA-您可以在程序中的任何线程上操作COM对象。