COM线程模型详解

上传人:ji****72 文档编号:37538774 上传时间:2018-04-18 格式:DOC 页数:13 大小:74KB
返回 下载 相关 举报
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-20作者:lop5712 来源:论坛本文关键词:本文关键词: COM 线程线程 模型模型 线程模型是一种数学模型,专门针对多线程编程而提供的算法,但也仅是算法, 不是实现。本文讲解 COM 提出的各个类型的线程模型,再说明 COM 运行时 期库是如何实现它们的,就像说明 Windows 是如何实现线程这个数学模型的 一样,最后指明一下跨套间调用和各种类型套间编写的要求以帮助理解。希望 读者对于 Windows 操作系统的线程这个概念相当熟悉,对何谓“线程安全的” 亦非常了解。COM 线程模型线程模型COM 提供的线程模型

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

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

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

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

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

7、了方便组件代码的编写只需调用 DispatchMessage 即可将方法调用的消息和普通的消息区分开来(通过隐藏 窗口的消息处理函数) 。外界对这个对象的调用都将转变成对这个隐藏窗口的消 息发送来实现同步。至于 COM 如何截获外界对对象的调用,则是利于代理对 象,后面再说明。值得注意的是,如果使用标准汇集法生成代理对象,则代理对象会根据是 进程内还是进程外的跨套间调用,来决定具体操作。如果外界线程和 STA 线程 在同一进程内,则代理对象将直接向 STA 线程中的隐藏窗口发送消息;如果不 在同一进程内(包括远程进程) ,代理对象将向 RPC 管理的一个线程池请求一 个线程(RPC 线程)来专

8、门向另一进程中的 STA 线程的隐藏窗口发送消息, 而不是代理对象直接发送消息,以防止外界线程由于网络等不稳定因素而导致 挂起。因为 COM 利用消息机制来实现 STA,因此 STA 套间里的线程必须实现消 息循环,否则 COM 将不能实现 STA 的要求。MTA 套间 这种类型的套间可以和多个线程及多个或没有对象相关联。根 据上面的 MTA 模型,可知只有这个套间里的线程才能访问这个套间里的对象, 和 STA 不同的只是可以多个线程同时访问对象。外界(不属于这个套间的线程)对这个套间里的对象的调用将会导致调用 线程(外界线程,也就是 STA 线程,因为 NA 没有线程)挂起,然后向 RPC

9、管理的一个线程池请求一个线程(RPC 线程,并已经进入了这个 MTA 套间)以调用那个对象的方法。对象返回后,调用线程被唤醒,继续运行。虽然可以 让 STA 线程直接调用对象(而不用像前述的挂起等待另一个线程来调用对象) , 但这是必须的,因为可能会有回调问题,比如这个 MTA 线程又反过来回调外 界线程中的组件对象(假设客户本身也是一个组件对象,这正是连接点技术) , 如果异步回调将可能发生错误。反过来,MTA 的线程访问 STA 里的对象时,COM 将把调用转换成对 STA 线程里那个隐藏窗口的一个消息发送,返回后再由 COM 转成结果返回给 MTA 的线程(如果使用标准汇集法生成标准代理

10、对象,则发生的具体情况就如 上面 STA 套间所述) 。因此 STA 和 MTA 都是只能由它们关联的线程调用它们 关联的对象。而根据上面所说,当 MTA 调 STA 或 STA 调 MTA,都会发生线 程切换,也就是说一个线程挂起而换成执行另一个线程。这是相当大的消耗 (需要从内核模式向用户模式转换,再倒转好几回) ,而 NA 就是针对这个设计 的。NA 套间 这种套间只和对象相关联,没有关联的线程,因此任何线程都可 以直接访问里面的对象,不存在 STA 的还是 MTA 的。外界(其实就是任何线程)对这个套间里面的调用都不需要挂起等待,而 是进入 NA 套间,直接调用对象的方法。NA 套间是

11、由 COM+提供的,COM+ 中的每个对象都有一个环境和其相绑定,环境记录了必要的信息,并监听对对 象的每一次调用,以保证当将对象的接口指针成员变量进行传递或回调时其操 作的正确性(保证执行线程在正确的套间内,MTA 线程就是通过将自己挂起以 等待 STA 线程的消息处理完毕来保证的) ,从而避免了调用线程的挂起,因此 这个代理(其实也就是环境的一部分)被称作轻量级代理(相对于 STA 套间和 MTA 套间的重量级代理需要挂起调用线程,发生线程切换) 。这个轻量级代理并不是永远都不发生线程切换。当 NA 对象里有个对指向 一个 STA 对象的指针的调用而调用线程不是那个 STA 对象关联的线程

12、时,调 用将会转成向被调用的 STA 对象的关联线程发送消息,此时照样会发生线程切 换。同理,如果那个对象是 MTA 的,而调用线程是 STA 线程时,依旧发生线 程切换。不过除此以外的大多数情况(即不在 NA 对象的方法中调用另一个套 间对象的方法)都不会发生线程切换,即使出现上面的情况也只有必要(MTA 调 NA 再调 MTA 就不用切换)才切换线程。根据上面所说,STA 其实和 MTA 逻辑上是完全一样的,只是一个是关联 一个线程,一个是关联多个线程而已。但把它们分开是必要的,因为线程安全 就是针对是一个线程还是多个线程。而 NA 之所以不关联线程是因为它的目的 是消除上面跨套间调用时产

13、生的线程切换损耗,关联线程没有任何意义。COM 强行规定(不遵守也没辙,因为全是 COM 实现套间的,根本没有插 手的余地)一个进程可以拥有多个 STA 的套间,但只能拥有一个 MTA 套间和 一个 NA 套间,我想这应该已经很容易理解了(要两个 MTA 套间或 NA 套间干 甚?) 。套间生成规则套间生成规则线程在进行大多数 COM 操作之前,需要先调用 CoInitialize 或 CoInitializeEx。调用 CoInitialize 告诉 COM 生成一个 STA 套间,并将当前 的调用线程和这个套间相关联。而调用 CoInitializeEx( NULL, COINIT_MUL

14、TITHREADED );告诉 COM 检查是否已经有了一个 MTA 套间, 没有则生成一个 MTA 套间,然后将那个套间和调用线程相关联。接着在调用 CoCreateInstance 或 CoGetClassObject 等创建对象的函数时,创建的对 象将以一个特定规则决定和哪个套间相关联(后叙)。这样完成后,就完成了 线程、对象和套间的关联(或绑定)。前面提到的决定对象去向的规则如下。当是进程内组件时,根据注册表项 InprocServer32ThreadingModel 和线程的不同,列于下表:创建线程关联的套间种类ThreadingModel 键值组件对象最后所在套间 STAApart

15、ment创建线程的套间 STAFree进程内的 MTA 套间 STABoth创建线程的套间 STA“或 Single进程内的主 STA 套间 STA Neutral进程内的 NA 套间 MTAApartment新建的一个 STA 套间 MTAFree 进程内的 MTA 套间 MTABoth进程内的 MTA 套间 MTA “或 Single 进程内的主 STA 套间 MTANeutral进程内的 NA 套间进程内的主 STA 套间是进程中第一个调用 CoInitialize 的线程所关联的套 间(即进程中的第一个 STA 套间)。后面说明为什么还来个进程内的主 STA 套间。当是进程外组件时,由

16、主函数调用 CoInitializeEx 或 CoInitialize 指定组 件所在套间,与上面的相同,CoInitialize 代表 STA,CoInitializeEx( NULL, COINIT_MULTITHREADED );代表 MTA,没有 NA。因为 NA 是 COM+提 供的,而 COM+服务只能提供给进程内服务器,因此只使用上面的注册表项的 规则决定 DLL 组件是否放进 NA 套间,而没有提供类似 CoInitializeEx( NULL, COINIT_NEUTRAL );来处理 EXE 组件。而且如果可以使用 CoInitializeEx( NULL, COINIT_NEUTRAL );将导致调用线程和 NA 套间相 关联了,违背了 NA 的线程模型,这也是为什么 ThreadingModel 键在 InprocServer32 键下。跨套间调用跨套间调用STA 线程 1 创建了一个 STA 对象,得到接口指针 IABCD*,接着它发起 STA 线程 2,并且将 IABCD*作为线程参数传入。在线

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

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