COM线程模型详解

上传人:壹****1 文档编号:563740169 上传时间:2023-07-16 格式:DOCX 页数:13 大小:29.23KB
返回 下载 相关 举报
COM线程模型详解_第1页
第1页 / 共13页
COM线程模型详解_第2页
第2页 / 共13页
COM线程模型详解_第3页
第3页 / 共13页
COM线程模型详解_第4页
第4页 / 共13页
COM线程模型详解_第5页
第5页 / 共13页
点击查看更多>>
资源描述

《COM线程模型详解》由会员分享,可在线阅读,更多相关《COM线程模型详解(13页珍藏版)》请在金锄头文库上搜索。

1、COM 线程模型详解开发者在线B更新时间:2007-10-作者:Iop5712来源:论坛本文关键词: COM 线程 模型线程模型是一种数学模型,专门针对多线程编程而提供的算法,但也仅是算法, 不是实现。本文讲解COM提出的各个类型的线程模型,再说明COM运行时期 库是如何实现它们的,就像说明 Windows 是如何实现线程这个数学模型的一 样,最后指明一下跨套间调用和各种类型套间编写的要求以帮助理解。希望读者 对于Windows操作系统的线程这个概念相当熟悉,对何谓线程安全的亦非常 了解。COM线程模型COM提供的线程模型共有三种:Single-Threaded Apartment (STA单

2、 线程套间)、Multithreaded Apartment (MTA 多线程套间)和 Neutral Apartment/Thread Neutral Apartment/Neutral Threaded Apartment(NA/TNA/NTA中立线程套间,由COM+提供)。虽然它们的名字都含有套 间这个词,这只是COM运行时期库(注意,不是COM规范,以下简称COM) 使用套间技术来实现前面的三种线程模型,应注意套间和线程模型不是同一个概 念。 COM 提供的套间共有三种,分别一一对应。而线程模型的存在就是线程规 则的不同导致的,而所谓的线程规则就只有两个:代码是线程安全的或不安全的,

3、即代码访问公共数据时会或不会发生访问冲突。由于线程模型只是个模型,概念 上的,因此可以违背它,不过就不能获得COM提供的自动同步调用及兼容等好 处了。STA 一个对象只能由一个线程访问(通过对象的接口指针调用其方法), 其他线程不得访问这个对象,因此对于这个对象的所有调用都是同步了的,对象 的状态(也就是对象的成员变量的值)肯定是正确变化的,不会出现线程访问冲 突而导致对象状态错误。其他线程要访问这个对象,必须等待,直到那个唯一的 线程空闲时才能调用对象。注意:这只是要求、希望、协议,实际是否做到是由 COM 决定的。如上所说,这个模型很像 Windows 提供的窗口消息运行机制, 因此这个线

4、程模型非常适合于拥有界面的组件,像 ActiveX 控件、 OLE 文档服 务器等,都应该使用STA的套间。MTA 一个对象可以被多个线程访问,即这个对象的代码在自己的方法中实 现了线程保护,保证可以正确改变自己的状态。这对于作为业务逻辑组件或干后 台服务的组件非常适合。因为作为一个分布式的服务器,同一时间可能有几千条 服务请求到达,如果排队进行调用,那么将是不能想像的。注意:这也只是一个 要求、希望、协议而已。NA 一个对象可以被任何线程访问,与 MTA 不同的是任何线程,而且当跨 套间访问时(后面说明),它的调用费用(耗费的CPU时间及资源)要少得多。 这准确的说都已经不能算是线程模型了,

5、它是结合套间的具体实现而提出的要 求,它和MTA不同的是COM的实现方式而已。COM套间Apartment 被翻译成套间或是单元,是线程模型的一个实现者,就像在操 作系统课程中讲到的线程只是一个数学模型,而Windows的线程、进程是它(数 学模型的线程、进程)的实现者。套间只是逻辑上的一个概念,实现时只是一个 结构(由COM管理)而已,记录着相关信息,如它的种类(只能是上面那三个, 至少现在是),并由 COM 根据那个结构进行相应的处理。下面说明这三种套间 的实现方式:STA套间一个套间如果是STA,那么那个套间有且只有一个线程和其关联, 有多个对象或没有对象和其关联,就像有多个线程和一个进

6、程关联一样,也就是 说套间那个结构和某个线程及多个对象之间有关系,关系具体是什么由COM说 得算,幸运的是COM正是按照上面的线程模型来定义互相之间关系的。根据上 面的算法,很容易就知道只有这个线程可以访问这个套间里的对象。COM是通过在STA套间里的线程中创建一个隐藏窗口,然后外界(这个套 间外的线程)对这个对象的调用都转变成对那个隐藏窗口发送消息,然后由这个 隐藏窗口的消息处理函数来实际调用组件对象的方法来实现STA的规则的。之 所以使用一个隐藏窗口是为了方便组件代码的编写只需调用 DispatchMessage 即可将方法调用的消息和普通的消息区分开来(通过隐藏窗 口的消息处理函数)。外

7、界对这个对象的调用都将转变成对这个隐藏窗口的消息 发送来实现同步。至于COM如何截获外界对对象的调用,则是利于代理对象, 后面再说明。值得注意的是,如果使用标准汇集法生成代理对象,则代理对象会根据是进 程内还是进程外的跨套间调用,来决定具体操作。如果外界线程和STA线程在 同一进程内,则代理对象将直接向STA线程中的隐藏窗口发送消息;如果不在 同一进程内(包括远程进程),代理对象将向RPC管理的一个线程池请求一个线 程(RPC线程)来专门向另一进程中的STA线程的隐藏窗口发送消息,而不是 代理对象直接发送消息,以防止外界线程由于网络等不稳定因素而导致挂起。因为COM利用消息机制来实现STA,因

8、此STA套间里的线程必须实现消 息循环,否则COM将不能实现STA的要求。MTA套间这种类型的套间可以和多个线程及多个或没有对象相关联。根据 上面的MTA模型,可知只有这个套间里的线程才能访问这个套间里的对象,和 STA不同的只是可以多个线程同时访问对象。外界(不属于这个套间的线程)对这个套间里的对象的调用将会导致调用线 程(外界线程,也就是STA线程,因为NA没有线程)挂起,然后向RPC管理 的一个线程池请求一个线程(RPC线程,并已经进入了这个MTA套间)以调用 那个对象的方法。对象返回后,调用线程被唤醒,继续运行。虽然可以让 STA 线程直接调用对象(而不用像前述的挂起等待另一个线程来调

9、用对象),但这是 必须的,因为可能会有回调问题,比如这个MTA线程又反过来回调外界线程中 的组件对象(假设客户本身也是一个组件对象,这正是连接点技术),如果异步 回调将可能发生错误。反过来,MTA的线程访问STA里的对象时,COM将把调用转换成对STA 线程里那个隐藏窗口的一个消息发送,返回后再由 COM 转成结果返回给 MTA 的线程(如果使用标准汇集法生成标准代理对象,则发生的具体情况就如上面 STA套间所述)。因此STA和MTA都是只能由它们关联的线程调用它们关联的 对象。而根据上面所说,当MTA调STA或STA调MTA,都会发生线程切换, 也就是说一个线程挂起而换成执行另一个线程。这是

10、相当大的消耗(需要从内核 模式向用户模式转换,再倒转好几回),而NA就是针对这个设计的。NA 套间 这种套间只和对象相关联,没有关联的线程,因此任何线程都可 以直接访问里面的对象,不存在STA的还是MTA的。外界(其实就是任何线程)对这个套间里面的调用都不需要挂起等待,而是 进入NA套间,直接调用对象的方法。NA套间是由COM+提供的,COM +中 的每个对象都有一个环境和其相绑定,环境记录了必要的信息,并监听对对象的 每一次调用,以保证当将对象的接口指针成员变量进行传递或回调时其操作的正 确性(保证执行线程在正确的套间内,MTA线程就是通过将自己挂起以等待STA 线程的消息处理完毕来保证的)

11、,从而避免了调用线程的挂起,因此这个代理(其 实也就是环境的一部分)被称作轻量级代理(相对于STA套间和MTA套间的重 量级代理需要挂起调用线程,发生线程切换)。这个轻量级代理并不是永远都不发生线程切换。当NA对象里有个对指向一 个STA对象的指针的调用而调用线程不是那个STA对象关联的线程时,调用将 会转成向被调用的STA对象的关联线程发送消息,此时照样会发生线程切换。 同理,如果那个对象是MTA 的,而调用线程是STA线程时,依旧发生线程切换。 不过除此以外的大多数情况(即不在NA对象的方法中调用另一个套间对象的方 法)都不会发生线程切换,即使出现上面的情况也只有必要(MTA调NA再调 M

12、TA就不用切换)才切换线程。根据上面所说,STA其实和MTA逻辑上是完全一样的,只是一个是关联一 个线程,一个是关联多个线程而已。但把它们分开是必要的,因为线程安全就是 针对是一个线程还是多个线程。而NA之所以不关联线程是因为它的目的是消除 上面跨套间调用时产生的线程切换损耗,关联线程没有任何意义。COM 强行规定(不遵守也没辙,因为全是 COM 实现套间的,根本没有插 手的余地)一个进程可以拥有多个STA的套间,但只能拥有一个MTA套间和一 个 NA 套间,我想这应该已经很容易理解了(要两个 MTA 套间或 NA 套间干 甚?)。套间生成规则线程在进行大多数COM操作之前,需要先调用Coln

13、itialize或ColnitializeEx。调用CoInitialize告诉COM生成一个STA套间,并将当前的调用线程和这个套间相关联。而调用 CoInitializeEx( NULL, COINIT_MULTITHREADED );告诉COM检查是否已经有了一个MTA套间, 没有则生成一个MTA套间,然后将那个套间和调用线程相关联。接着在调用 CoCreateInstanee或CoGetClassObject等创建对象的函数时,创建的对象 将以一个特定规则决定和哪个套间相关联(后叙)。这样完成后,就完成了线程、 对象和套间的关联(或绑定)。前面提到的决定对象去向的规则如下。当是进程内组

14、件时,根据注册表项InprocServer32ThreadingModel 和线程的不同,列于下表:创建线程关联的套间种类ThreadingModel 键值组件对象最后所在套间STAApartme nt创建线程的套间STAFree进程内的MTA套间STABoth创建线程的套间STA或 Single进程内的主STA套间STANeutral进程内的NA套间MTAApartme nt新建的一个STA套间MTAFree进程内的MTA套间MTABoth进程内的MTA套间MTA或 Single进程内的主STA套间MTANeutral进程内的NA套间进程内的主STA套间是进程中第一个调用CoInitiali

15、ze的线程所关联的套 间(即进程中的第一个STA套间)。后面说明为什么还来个进程内的主STA套 间。当是进程外组件时,由主函数调用 CoInitializeEx 或 CoInitialize 指定组 件所在套间,与上面的相同,Coinitialize代表STA,CoinitializeEx( NULL, COINIT_MULTITHREADED );代表 MTA,没有 NA。因为 NA 是 COM+ 提供 的,而COM+服务只能提供给进程内服务器,因此只使用上面的注册表项的规 则决定 DLL 组件是否放进 NA 套间,而没有提供类似 CoInitializeEx( NULL, COINIT_N

16、EUTRAL ); 来 处 理 EXE 组 件 。 而 且 如 果 可 以 使 用 CoinitializeEx( NULL, COINIT_NEUTRAL );将导致调用线程和 NA套间相关 联了, 违背了 NA 的线程模型, 这也是为什么 ThreadingModel 键在 InprocServer32 键下。跨套间调用STA线程1创建了一个STA对象,得到接口指针IABCD*,接着它发起 STA线程2,并且将IABCD*作为线程参数传入。在线程2中,调用 IABCD:Abc ()方法,成功或者失败天注定。由于线程2所在的STA套间不同 于线程1所在的STA套间,这样线程2就跨套间调用另一个套间的对象了。按 照前述的STA规则,IABCD

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文 > 其它学术论文

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号