根据上面所说,STA其实和MTA逻辑上是完全一样的,只是一个是关联一个线程,一个是关联多个线程而已。但把它们分开是必要的,因为线程安全就是针对是一个线程还是多个线程。而NA之所以不关联线程是因为它的目的是消除上面跨套间调用时产生的线程切换损耗,关联线程没有任何意义。
COM强行规定(不遵守也没辙,因为全是COM实现套间的,根本没有插手的余地)一个进程可以拥有多个STA的套间,但只能拥有一个MTA套间和一个NA套间,我想这应该已经很容易理解了(要两个MTA套间或NA套间干甚?)。
套间生成规则
线程在进行大多数COM操作之前,需要先调用CoInitialize或CoInitializeEx。调用CoInitialize告诉COM生成一个STA套间,并将当前的调用线程和这个套间相关联。而调用CoInitializeEx( NULL, COINIT_MULTITHREADED );告诉COM检查是否已经有了一个MTA套间,没有则生成一个MTA套间,然后将那个套间和调用线程相关联。接着在调用CoCreateInstance或CoGetClassObject等创建对象的函数时,创建的对象将以一个特定规则决定和哪个套间相关联(后叙)。这样完成后,就完成了线程、对象和套间的关联(或绑定)。
前面提到的决定对象去向的规则如下。
当是进程内组件时,根据注册表项<CLSID>\InprocServer32\ThreadingModel和线程的不同,列于下表:
创建线程关联的套间种类 | ThreadingModel键值 | 组件对象最后所在套间 |
STA | Apartment | 创建线程的套间 |
STA | Free | 进程内的MTA套间 |
STA | Both | 创建线程的套间 |
STA | ""或Single | 进程内的主STA套间 |
STA | Neutral | 进程内的NA套间 |
MTA | Apartment | 新建的一个STA套间 |
MTA | Free | 进程内的MTA套间 |
MTA | Both | 进程内的MTA套间 |
MTA | ""或Single | 进程内的主STA套间 |
MTA | Neutral | 进程内的NA套间 |
进程内的主STA套间是进程中第一个调用CoInitialize的线程所关联的套间(即进程中的第一个STA套间)。后面说明为什么还来个进程内的主STA套间。