COM套间

转载 2011年01月25日 23:24:00

线程模型是一种数学模型,专门针对多线程编程而提供的算法,但也仅是算法,不是实现。本文讲解COM提出的各个类型的线程模型,再说明COM运行时期库是如何实现它们的,就像说明Windows是如何实现线程这个数学模型的一样,最后指明一下跨套间调用和各种类型套间编写的要求以帮助理解。希望读者对于Windows操作系统的线程这个概念相当熟悉,对何谓“线程安全的”亦非常了解。
COM线程模型

  COM提供的线程模型共有三种:Single-Threaded Apartment(STA 单线程套间)、Multithreaded Apartment(MTA 多线程套间)和Neutral Apartment/Thread Neutral Apartment/Neutral Threaded Apartment(NA/TNA/NTA 中立线程套间,由COM+提供)。虽然它们的名字都含有套间这个词,这只是COM运行时期库(注意,不是COM规范,以下简称COM)使用套间技术来实现前面的三种线程模型,应注意套间和线程模型不是同一个概念。COM提供的套间共有三种,分别一一对应。而线程模型的存在就是线程规则的不同导致的,而所谓的线程规则就只有两个:代码是线程安全的或不安全的,即代码访问公共数据时会或不会发生访问冲突。由于线程模型只是个模型,概念上的,因此可以违背它,不过就不能获得COM提供的自动同步调用及兼容等好处了。

  STA 一个对象只能由一个线程访问(通过对象的接口指针调用其方法),其他线程不得访问这个对象,因此对于这个对象的所有调用都是同步了的,对象的状态(也就是对象的成员变量的值)肯定是正确变化的,不会出现线程访问冲突而导致对象状态错误。其他线程要访问这个对象,必须等待,直到那个唯一的线程空闲时才能调用对象。注意:这只是要求、希望、协议,实际是否做到是由COM决定的。如上所说,这个模型很像Windows提供的窗口消息运行机制,因此这个线程模型非常适合于拥有界面的组件,像ActiveX控件、OLE文档服务器等,都应该使用STA的套间。

  MTA 一个对象可以被多个线程访问,即这个对象的代码在自己的方法中实现了线程保护,保证可以正确改变自己的状态。这对于作为业务逻辑组件或干后台服务的组件非常适合。因为作为一个分布式的服务器,同一时间可能有几千条服务请求到达,如果排队进行调用,那么将是不能想像的。注意:这也只是一个要求、希望、协议而已。


  NA 一个对象可以被任何线程访问,与MTA不同的是任何线程,而且当跨套间访问时(后面说明),它的调用费用(耗费的CPU时间及资源)要少得多。这准确的说都已经不能算是线程模型了,它是结合套间的具体实现而提出的要求,它和MTA不同的是COM的实现方式而已。

 

COM套间

  Apartment被翻译成套间或是单元,是线程模型的一个实现者,就像在操作系统课程中讲到的线程只是一个数学模型,而Windows的线程、进程是它(数学模型的线程、进程)的实现者。套间只是逻辑上的一个概念,实现时只是一个结构(由COM管理)而已,记录着相关信息,如它的种类(只能是上面那三个,至少现在是),并由COM根据那个结构进行相应的处理。下面说明这三种套间的实现方式:

  STA套间 一个套间如果是STA,那么那个套间有且只有一个线程和其关联,有多个对象或没有对象和其关联,就像有多个线程和一个进程关联一样,也就是说套间那个结构和某个线程及多个对象之间有关系,关系具体是什么由COM说得算,幸运的是COM正是按照上面的线程模型来定义互相之间关系的。根据上面的算法,很容易就知道只有这个线程可以访问这个套间里的对象。

  COM是通过在STA套间里的线程中创建一个隐藏窗口,然后外界(这个套间外的线程)对这个对象的调用都转变成对那个隐藏窗口发送消息,然后由这个隐藏窗口的消息处理函数来实际调用组件对象的方法来实现STA的规则的。之所以使用一个隐藏窗口是为了方便组件代码的编写——只需调用DispatchMessage即可将方法调用的消息和普通的消息区分开来(通过隐藏窗口的消息处理函数)。外界对这个对象的调用都将转变成对这个隐藏窗口的消息发送来实现同步。至于COM如何截获外界对对象的调用,则是利于代理对象,后面再说明。

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

  因为COM利用消息机制来实现STA,因此STA套间里的线程必须实现消息循环,否则COM将不能实现STA的要求。

  MTA套间 这种类型的套间可以和多个线程及多个或没有对象相关联。根据上面的MTA模型,可知只有这个套间里的线程才能访问这个套间里的对象,和STA不同的只是可以多个线程同时访问对象。

  外界(不属于这个套间的线程)对这个套间里的对象的调用将会导致调用线程(外界线程,也就是STA线程,因为NA没有线程)挂起,然后向RPC管理的一个线程池请求一个线程(RPC线程,并已经进入了这个MTA套间)以调用那个对象的方法。对象返回后,调用线程被唤醒,继续运行。虽然可以让STA线程直接调用对象(而不用像前述的挂起等待另一个线程来调用对象),但这是必须的,因为可能会有回调问题,比如这个MTA线程又反过来回调外界线程中的组件对象(假设客户本身也是一个组件对象,这正是连接点技术),如果异步回调将可能发生错误。

  反过来,MTA的线程访问STA里的对象时,COM将把调用转换成对STA线程里那个隐藏窗口的一个消息发送,返回后再由COM转成结果返回给MTA的线程(如果使用标准汇集法生成标准代理对象,则发生的具体情况就如上面STA套间所述)。因此STA和MTA都是只能由它们关联的线程调用它们关联的对象。而根据上面所说,当MTA调STA或STA调MTA,都会发生线程切换,也就是说一个线程挂起而换成执行另一个线程。这是相当大的消耗(需要从内核模式向用户模式转换,再倒转好几回),而NA就是针对这个设计的。

  NA套间 这种套间只和对象相关联,没有关联的线程,因此任何线程都可以直接访问里面的对象,不存在STA的还是MTA的。

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

  这个轻量级代理并不是永远都不发生线程切换。当NA对象里有个对指向一个STA对象的指针的调用而调用线程不是那个STA对象关联的线程时,调用将会转成向被调用的STA对象的关联线程发送消息,此时照样会发生线程切换。同理,如果那个对象是MTA的,而调用线程是STA线程时,依旧发生线程切换。不过除此以外的大多数情况(即不在NA对象的方法中调用另一个套间对象的方法)都不会发生线程切换,即使出现上面的情况也只有必要(MTA调NA再调MTA就不用切换)才切换线程。

  根据上面所说,STA其实和MTA逻辑上是完全一样的,只是一个是关联一个线程,一个是关联多个线程而已。但把它们分开是必要的,因为线程安全就是针对是一个线程还是多个线程。而NA之所以不关联线程是因为它的目的是消除上面跨套间调用时产生的线程切换损耗,关联线程没有任何意义。

  COM强行规定(不遵守也没辙,因为全是COM实现套间的,根本没有插手的余地)一个进程可以拥有多个STA的套间,但只能拥有一个MTA套间和一个NA套间,我想这应该已经很容易理解了(要两个MTA套间或NA套间干甚?)。

 

 

 

°套间不等于线程,它只是一个逻辑概念,实现为一个结构体
  °环境不等于线程,它只是一个逻辑概念,实现为一个结构体,可以理解为对象的配置 
  -
  °同一进程可以有多个STA,但是只能有一个MTA和一个NTA
  °同一套间,无论是何种套间,均可包含一个或多个环境
  °同一环境可以包含一个或多个对象
  °同一环境只能存在于一个套间当中
  °同一COM对象只能存在于一个环境当中 
  -
  °一个MTA可以与多个线程绑定
  °一个STA只能与一个线程绑定
  °一个NTA不与任何线程绑定,里面只包含了COM对象 
  -
  °同一进程中所有支持MTA线程模式的COM对象均放在同一个MTA中
  °同一进程中所有支持NTA线程模式的COM对象均放在同一个NTA中 
  -
  °任何跨越环境的对象间相互调用,都需要列集/散列
  °任何跨越了套间、进程、主机的对象间相互调用,都需要列集/散列 
  -
  °同一套间,仅仅跨越环境的对象间相互调用使用无需线程切换的轻量级代理
  °同一进程,跨越了套间的对象间相互调用使用需要进行线程切换的xxx代理(待查)
  °同一主机,跨越了进程的对象间相互调用使用LRPC代理
  °跨越了主机的对象间相互调用使用RPC代理 
  -
  °LRPC和RPC通称ORPC(面向对象的远程过程调用协议)

相关文章推荐

COM的套间与线程

最近学习COM的编程,开发工具是VC6.0的ATL。用两个线程进行测试,主线程(Main Thread)和一个新开的线程(New Thread)。两个线程实例化的同一个COM组件。主要测试的是COM的...

翻译:理解COM套间(第一部分)

最近在写一个 oledb provider,涉及到线程套间的问题,搜到下面的文章,感觉说的透彻,转了过来。 这个oledb provider是为了在asp.net程序中供ado.net使用,通过Sy...

COM线程模型 - MTA接口 (STA套间调用MTA对象)

 http://support.microsoft.com/kb/150777
  • zj510
  • zj510
  • 2014年09月04日 15:42
  • 1574

COM套间

[1] COM套间的产生原因 COM组件由于经常在系统中只存在一个实例,给出的多个接口事实上只是对一个对象实例的引用,所以,在多线程的情况下,会存在重入问题。 COM组件的作者有可能在他的代码中做...
  • lltaoyy
  • lltaoyy
  • 2011年08月13日 21:27
  • 718

翻译:理解COM套间(第二部分)

转自:http://blog.sina.com.cn/s/blog_56dee71a0100ntr9.html 英文原版:http://www.codeguru.com/cpp/com-tech/a...

理解COM套间(第一部分)

编写拙作《关于COM组件线程模型的实验》的过程中,发现自己无法合理解释特定情况下程序的运行情况。为更深入理解COM的线程模型,合理解释程序运行情况,找了一些资料看。发现一篇英文文章不错,特地翻译出来。...

深入理解COM的单套间--第一部分(转载)

理解套间这个概念对于COM编程非常重要!
  • ThinkHY
  • ThinkHY
  • 2011年05月22日 23:36
  • 1252

COM单线程套间详解

作者: Ocean 发表时间: 2010年7月25日 本文链接: http://www.soft-bin.com/html/2010/07/25/com%e5%8d%95%e7%ba%bf%e7%...
  • patdz
  • patdz
  • 2013年01月07日 19:34
  • 2018

[转]COM线程模型-套间

[转]COM线程模型-套间 COM线程模型-套间 来源: http://blog.csdn.net/crybird/archive/2008/10/11/3057067.asp...

理解 COM 套间

简序   大学毕业前的最后一学期,在一家公司实习,当时的工作需要用到一些操作系统提供的组件。那时候只知道COM这个名词,并不知道到底是怎么回事,只知道 上网到处找别人的源码解决自己的问题;那...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:COM套间
举报原因:
原因补充:

(最多只允许输入30个字)