COM线程模型


1.   概述  

本文是一篇读书笔记,参考COM相关书籍,总结了COM的线程模型,包括套间线程、自由线程、单线程套间、多线程套间、列集等相关概念。

2.   Win32线程

由于COM直接使用了Win32线程,因此有必要先讨论一下Win32的线程。Win32系统线程本身只有一种,根据应用模型可分为两种: 工作线程和UI线程

  • 工作线程就是一条执行线索,没有消息概念,执行完后线程就会退出。
  • UI线程与工作线程最大的区别就是它包含消息队列,当线程首次调用Win32 User或GDI函数时(比如创建窗口),操作系统会为它建立一个消息队列。为了能够正确处理消息队列中的消息,UI线程通常会包含如下的消息循环:
while(GetMessage(&msg, NULL, 0, 0))  
{
   TranslateMessage (&msg);
   DispatchMessage (&msg);
}

COM使用的线程类型与Win32的两种线程类型是相同的,与UI线程相对应的是套间线程,它的主函数也有消息循环,与工作线程对应的是自由线程

3.   套间的概念

套间是一个逻辑上的概念,用于控制多线程访问COM组件。可以把套间看作COM线程模型的实现者,调度、切换COM对象执行的线程环境,保证COM对象的多线程调用正常运行。可以把进程中的COM对象想象为分成若干组,每一组就是一个套间。属于这个套间的线程,可以直接调用对象,不属于这个套间的线程,要通过代理才能调用对象。在实现上,套间是保存在线程TLS中的一个数据结构,借用该结构使套间和线程之间建立起关联。

有三种套间:STA、MTA、TNA,不过对于TNA不熟悉,这里暂只讨论单线程套间和多线程套间。

STA(单线程套间)

  • 一个进程可以包含多个STA套间
  • 每个STA套间包含唯一一个线程,与线程有一一对应关系,这个线程就是套间线程

MTA(多线程套间)

  • 一个进程至多只有一个MTA套间
  • MTA套间中可以包含一个或者多个线程,这些线程是自由线程

4.   STA和套间线程

首先考虑Win32程序中UI线程和它创建的窗口,用户给这个窗口发送一条消息时,Windows将消息放到这个线程的消息队列中,线程取出这些消息然后分发到指定的窗口,调用窗口过程进行处理,此时这些操作都是在创建窗口的线程上串行执行的,用户不必考虑同步的问题。

类似的,套间线程将拥有其创建的COM对象,同时创建一个隐藏的窗口用于同步和分发消息。其他线程的代码无法直接调用对象的成员函数,只能通过代理/存根调用此对象,这些调用会以消息形式发送到套间线程中,套间线程通过消息循环调用相关的控制函数,所以这些调用都会被自动同步。

STA创建步骤

  1. 在一个线程中调用CoInitializeEx(NULL,COINIT_APARTMENTTHREADED) 或者CoInitialize(NULL)。COM将创建一个STA套间并与当前线程关联,该线程即成为套间线程。
  2. 线程中需要包含消息泵,否则来自其他线程的调用将永远无法返回。
  3. 在线程结束之前,调用CoUninitialize结束套间。

5.   MTA和自由线程

一个进程最多只能有一个MTA,第一次在某个线程中调用CoInitializeEx(NULL, COINIT_MULTITHREADED)时,会创建一个MTA,然后套间把当前线程和自己关联在一起,线程被标记为自由线程。其它线程再调用(在同一进程中)的时候,这个MTA会把这些个线程也关联在一起,并标记为自由线程。

一个MTA可以关联多个线程。所有的关联线程都可以调用套间中的COM对象。这就涉及到同步问题,需要组件编写者自己解决。MTA线程创建的对象并没有生存在任何特定的线程中,而是生存在MTA中。

6.   套间之间传递接口指针

         不能在套间之间直接传递原始接口指针,需要通过列集(或者叫封送,Marshaling)和散集。Windows NT4.0及更高版本提供一对名为CoMarshalInterThreadInterfaceInStream 和 CoGetInterfaceAndReleaseStream 的 API 函数完成该功能。

         这一对函数的实现是比较智能的,在不需要列集时是不会列集的,比如在MTA的不同线程间传递接口指针,因此一个良好的做法是任何时候在线程间传递接口指针时都调用该函数。

7.   COM组件的调用

  •   不同进程之间,不管什么线程类型,都需要proxy/stub
  • 在同一个进程内不同STA之间,也需要proxy/stub
  • 在STA内部,一个对象调用另一个对象的方法不需要proxy/stub
  • 从MTA调用STA,需要proxy/stub
  •  在MTA内部,对象和调用者之间调用不需要proxy/stub,调用直接在客户线程中执行
  • 从STA或者其他进程调用MTA,需要proxy/stub ,调用在RPC线程上执行

8.   参考书目

《COM技术内幕》  ----Dale Rogerson著

《COM原理与应用》 ----潘爱民 著


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值