你能用自己的话解释STA和MTA吗?
什么是公寓线程,它们只与COM有关吗?如果是这样,为什么?
COM线程模型称为"单元"模型,其中初始化COM对象的执行上下文与单个线程(单线程单元)或多个线程(多线程单元)相关联.在此模型中,COM对象一旦在公寓中初始化,就会在其运行时间内成为该公寓的一部分.
STA模型用于非线程安全的COM对象.这意味着他们不会处理自己的同步.这个的常见用途是UI组件.因此,如果另一个线程需要与对象交互(例如按下表单中的按钮),则将消息编组到STA线程上.窗口形成消息泵系统就是一个例子.
如果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中,它都会更加容易.
我发现现有的解释太gobbledygook.这是我用简单的英语解释的:
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的.
Apartment Threads,如果一个线程与它正在使用的对象住在同一个公寓,那么它就是一个公寓线程.我认为这只是一个COM概念,因为它只是一种谈论它们与之交互的对象和线程的方式......
每个承载COM或OLE控件的EXE都定义它的公寓状态.公寓状态默认为STA(并且对于大多数程序应该是STA).
STA - 必要时所有OLE控件必须存在于STA中.STA意味着必须始终在UI线程上操作COM对象,并且不能将其传递给其他线程(非常类似于MFC中的任何UI元素).但是,您的程序仍然可以有许多线程.
MTA - 您可以在程序中的任何线程上操作COM对象.
据我所知,'Apartment'用于保护COM对象免受多线程问题的影响.
如果COM对象不是线程安全的,则应将其声明为STA对象.然后只有创建它的线程才能访问它.创建线程应该将自己声明为STA线程.在引擎盖下,线程将STA信息存储在其TLS(线程本地存储)中.我们将此行为称为线程进入STA公寓.当其他线程想要访问此COM对象时,它应该封送对创建线程的访问.基本上,创建线程使用消息机制来处理入站调用.
如果COM对象是线程安全的,则应将其声明为MTA对象.可以通过多线程访问MTA对象.