Com线程模型及工作方式

COM 对象可以用于一个进程的多线程。“单线程单元” (STA) 和“多线程单元” (MTA) 术语用于为描述对象与线程间的关系、对象间的并行关系、使用何种方法将调用传递给对象的方式以及在线程间传递接口指针的规则而建立的概念框架。组件及其客户可以在 COM 目前支持的以下两个单元模型之间进行选择:

  1. 单线程单元模型 (STA):进程中一个或多个线程使用 COM ,并且 COM 对象的调用由 COM 进行同步。在线程间对接口进行编组。单线程单元模型的退化情况(其中,在给定的进程中只有一个线程使用 COM)被称为单线程模型。以前的 Microsoft 信息与文档曾经将 STA 模型简单地称为“单元模型”。
  2. 多线程单元模型 (MTA):一个或多个线程使用 COM,并且由所有与 MTA 有关的线程直接调用与 MTA 有关的 COM 对象,而在调用者和对象间没有系统代码的插入。由于多个同步客户可能将或多或少地同时调用对象(同时在多个处理器系统上),所以对象必须自己同步其内部状态。在线程间没有接口编组。

“单元”有几个相互关连的方面。首先,从并行的角度来讲它是一个逻辑结构,例如线程与一系列 COM 对象是如何关联的。其次,它是编程人员必须遵守的一系列规则,以便可以从 COM 环境获取期望的并行操作。最后,它是系统提供的代码,用于帮助程序员管理针对 COM 对象的线程并行。

“单元”术语来自一个比喻,进程在其中被设想成一个完全离散的实体,就好像一个“大厦”被分成一系列相关而又不同的称为“单元”的“区域”一样。单元是一个“逻辑容器”,它在对象间和线程间(某些情况下)创建关联。虽然可能存在与 STA 模型中的某个单元逻辑关联的单个线程, 但线程不是单元。虽然每个对象都与一个且仅一个单元相关联,但对象不是单元。但是,单元不仅仅是一个逻辑结构;其规则描述了 COM 系统的行为。如果不遵守单元模型的规则,COM 对象将不能正常工作。

 

单线程单元 (STA) 是一系列与特定线程相关的 COM 对象。这些对象通过由该线程创建(或者更精确地说,率先在该线程上暴露给 COM 系统(典型地通过编组))的方式与单元相关联。STA 被当作对象或代理“生存”的地方。如果对象或代理需要被另一个单元访问(在同一个或不同的进程中),其接口指针必须被编组到创建新代理的该单元中。如果遵守单元模型规则,则在同一进程中不允许从其它线程直接调用该对象;这将违反在指定单元内的所有对象都应在一个单线程上运行的规则。之所以有规则是因为如果在其它线程上运行,多数在 STA 下运行的代码将不能正常运行。

与 STA 相关的线程必须调用 CoInitialize 或 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED),而且必须为相关的对象检索和发送窗口信息以接收传入的调用。如本文后面所讲述的,COM 使用窗口信息向 STA 中的对象发送和同步调用。

“主 STA”是在给定进程中首先调用 CoInitialize 或 CoInitializeEx(NULL,COINIT_APARTMENTTHREADED)的线程。如本文后面所述,由于一些进程内对象总是在主 STA 中加载,所以进程的主 STA 必须始终保持有效直到所有 COM 工作完成为止。

一个进程可以有许多 STA,但最多只能有一个 MTA。MTA 包含一个或多个线程。每个 STA 只有一个线程。一个线程最多只能属于一个单元。对象只能属于一个单元。接口指针应该总是在单元间进行编组(虽然编组的结果可能是一个直接指针而不是一个代理)。

 

单线程单元模型



进程内服务器被“加载到”单元的明确定义在以下的两个步骤中进行解释:

  1. 如果包含进程内服务器类的 DLL 以前还没有通过操作系统加载程序进行加载(映射到进程地址空间),则该执行操作且 COM 获得 DLL 输出的 DLLGetClassObject 函数地址。如果 DLL 以前已经过与任何单元相关的线程进行加载,请跳过此步骤。
  2. COM 使用与“加载”单元相关的线程(或对于 MTA 情况,一个线程)来调用由寻找所需类的 CLSID 的 DLL 输出的 DllGetClassObject 函数。然后,返回的集对象用于创建该类对象的实例。

    每当一个客户调用 CoGetClassObject/CoCreateIntance[Ex] 时,即使是从同一单元内,都会发生第二个步骤(由 COM 调用 DllGetClassObject)。换而言之,DllGetClassObject 可以由与同一单元相关的线程调用多次;这完全取决于在该单元中有多少个客户正在试图为该类获得一个类集对象的访问权限。

最终,类实现的编写者和指定类集的 DLL 包的编写者拥有按 DllGetClassObject 函数调用确定返回何种集对象的完全自由。因为在单 DLL 范围的 DllGetClassObject() 进入点“后面”的代码拥有最优先和最终决定权限,所以 DLL 包的编写者拥有最终决定权。三种典型的可能性分别为:

  1. DllGetClassObject 根据调用线程返回一个唯一类集对象(意味着一个 STA 对应一个类集对象,且潜在情况下在 MTA 内对应多个类集)。
  2. 不管调用线程的身份如何,或与调用线程相关的单元种类如何,DllGetClassObject 总是返回相同的类集。
  3. DllGetClassObject 根据调用单元返回一个唯一的类集对象(在 STA 和 MTA 中一个单元对应一个)。

DllGetClassObject 调用与实际返回的类集对象之间还有其它的可能存在关系(如针对 DllGetClassObject 调用的新类集对象),但是他们目前似乎不是非常有用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值