COM提供的线程模型共有三种:
Single-Threaded Apartment(STA 单线程套间);
Multithreaded Apartment(MTA 多线程套间);
Neutral Apartment/Thread Neutral Apartment/Neutral Threaded Apartment(NA/TNA/NTA 中立线程套间,由COM+提供)。
解释:
STA: 一个对象只能由一个线程访问(通过对象的接口指针调用其方法),其他线程不得访问这个对象,因此对于这个对象的所有调用都是同步了的;这个模型很像Windows提供的窗口消息运行机制,因此这个线程模型非常适合于拥有界面的组件,像ActiveX控件、OLE文档服务器等,都应该使用STA的套间。
MTA 一个对象可以被多个线程访问,即这个对象的代码在自己的方法中实现了线程保护,保证可以正确改变自己的状态。这对于作为业务逻辑组件或干后台服务的组件非常适合。
NA 一个对象可以被任何线程访问,与MTA不同的是任何线程,而且当跨套间访问时(后面说明),它的调用费用(耗费的CPU时间及资源)要少得多。
形象表达:
公寓(Apartment)有的译文译作"套间"。这个术语抽象的是COM对象的生存空间,你还真的可以想象成公寓,线程就是住在公寓里的人。
单线程公寓(Single-Threaded Apartment STA) 这种房间是供有钱人住的单人间,设备齐全,服务周到。
多线程公寓(Multithreaded Apartment MTA) 住在这种房间里的人条件就差多了,那么多人就挤在一个大房间里头,可是他们自强不息。个个健壮得不得了。
在Windows中COM的线程模型在建立在Win32线程模型的基础上的。
1、公寓, COM 决定支持强大的多线程,于是引入了这个概念,公寓决定了线程与外界通信的方式。每一个与COM对象打交道的线程必须先决定要进入哪种公寓。
2、单线程公寓,这种公寓本身只能包含一个线程,通过调用CoInitialize(NULL)进入。对该公寓中线程所拥有的COM对象的调用被队列化,只有当一个调用结束后,另个调用才会开始。
3、多线程公寓,这种公寓可以包含任意多的线程(具体数目由操作系统决定)。一个进程里头只能包含一个这种公寓,所有调用CoInitializeEx(NULL, COINIT_MULTITHEADED)都会进入这个公寓。对该公寓中线程所拥有的COM对象的调用是直接的(先不考虑跨进程的情况),包括本公寓中的线程与其它的STA线程。
单线程公寓与多线程公寓 的本质差别有哪些?
单线程公寓实现同步,有很多COM库的干预,包括将外部的调用转化成窗口消息,然后那个特别的隐藏窗口的窗口函数把窗口消息转化成COM对象的函数调用。这样的模型可以减小开发组件的难度,可是,却牺牲了效率。
多线程公寓把实现同步任务全部交给了组件自己,所以在这种公寓中生存的COM对象必须足够健壮,考虑各种同步问题,不至于多个线程在调用对象的成员函数时会打架。
公寓,线程,对象的关系
公寓是这里面最大的单位,它是线程的容器。
如果调用CoInitialize(0),COM库会创建一个STA(注意,是"创建"),你的线程将属于这个公寓,并且是这个公寓的唯一成员。
如果CoInitializeEx(NULL, COINIT_MULTITHEADED),而且是第一个要求进入MTA的线程,COM库会创建一个MTA,其它后面调用CoInitializeEx(NULL, COINIT_MULTITHEADED)的线程会直接进入(注意,我用的"进入")已有MTA。本来线程是一个运行的实体,不会分配资源,可是在 COM的线程模型里一个对象与创建它的线程是紧密相关的,称对象归属于某个线程,至于这种归属关系是在COM库内怎么管理,我们先不去管它,以后我们把线程A创建的对象说成是线程A的对象就行了(有一个例外,得说说,有一种Single 类型的COM对象,这种对象基实就是COM在提出线程模型前的产物,这种对象总是归属于主STA线程,即第一个调用CoInitialize(0)的线程。)