一点心得:组件的线程模型
关于组件的线程模型
一,两种线程模型
STA(Single Threaded Apartment)
在STA模型中,一个Apartment里只允许有一个线程,可以有多个实例,一个进程中可以有多个STA。每个STA里都必须有消息处理部分。所有对实例的访问都在WINDOWS的消息传递机制下,被线程串行化了。套间与套间之间可以并发执行。
MTA(Multiple Threaded Apartment)
在MTA模型中,一个Apartment中可以有多个线程,但是一个进程中只有一个MTA。MTA中不需要消息处理。
(其实在WINDOWS2000还有第三种模型NTA,由于暂时用不到那么高级的功能特性,因些没有去了解和掌握它。)
任何要用到COM的线程,都需要标明它的线程模型,而且一旦标明线程模型,线程的同步性便不能更改。很明显,客户端和服务端都需要标明其线程模型。
二,线程模型的联系
这里只考虑进程外服务。由于进程外服务和客户程序属于不同的进程,从而必定属于不同的APARTMENT,而COM规定,套间(Inter-apartment)联系必须列集(Marshal)。也就是说不论客户与服务组件联系肯定要通过列集,而列集可以掩盖它们的不同的线程模型。
在STA中,由于只有一个线程,线程中的多个实例会相互干扰。如果客户端是STA,那么其中所有实例的方法必定完全是顺序执行的,这很容易理解。如果服务端是STA,那么所有客户对组件方法的调用也都是串行的,也就是说,即使客户端是并行调用一个实例的一些方法,实际执行时仍是串行执行的。除非客户端和服务端都是MTA,在一个客户端才能实现并行访问。当然,如果服务端是MTA,而客户端是STA,那么多个客户的访问是并行的,而在一个客户内部的访问是串行的。
三,组件的线程模型
组件的线程模型分为四种:Single, Apartment, Both, Free。简单地说,它们分别对应:STA(main),STA,STA and MTA, MTA。对象的线程模型的含义是“它生活在什么样的线程模型里”,就好像划成分一样,一出生就确定,然后就不能再改变。
根据MSDN上的说明,尽量不要用Single和Free,所以这里只讨论Apartment和Both。Apartment类的对象只能生活在STA中,如果服务程序本身是STA,那么它就不得不重新为每个实例生成一个新的Apartment。由于服务程序和组件生活在不同的套间,每次访问都不得不进行套间切换和列集,这样是非常低效的。但如果服务程序是STA,那么就可以直接调用了。Both类的对象即可以在STA中,也可以在MTA中,不管服务程序属于哪一类,都可以直接调用,因此非常高效。
Apartment的优势在于它不必是线程安全的,但对于全局变量和静态变量,仍然要提供同步保持机制。Both类的对象必须是线程完全的。