【转载】COM的多线程模型

原文:COM的多线程模型

COM的多线程模型是COM技术里头最难以理解的部分之一,很多书都有涉及但是都没有很好的讲清楚。很多新人都会在这里觉得很迷惑,google大神能搜到一篇vckbase上的文章,但是个人建议还是不要看的好几乎是胡说八道在乱搞。

COM自己其实并没有任何多线程模型,所以他用的多线程模型还是WIN32里头的那一套线程和同步对象。作为准备,这里先简单讲一下WIN32的线程和同步。作为惯例一讲WIN32的线程和同步对象就要把进程、线程这两个东西讲一遍,但是这里不讲,因为会看COM的对这部分已经很熟悉了,如果不熟悉的话建议也不要看COM了先回头看看《Windows核心编程》和《Windows高级编程》。WIN32的线程可以分为两种,UI线程和工作线程。UI线程是一种与一个窗口绑定的线程,其特点是包含一个窗口一个消息循环和一个窗口过程,由于消息循环的存在导致了其天生就具有一种同步机制:任何发送到该线程的消息都会被消息循环同步,不会有任何两个或以上的消息同时被窗口过程处理,所有消息都会被消息循环串行化;工作线程则可以认为是一个函数在一个线程上的一次运行,这种线程不具备任何自带的同步机制,如果要对两个工作者线程实施某种同步则只能使用WIN32的同步对象如CriticalSection或者Event等等。

接下来看COM的多线程模型,从VS2005的ATL工程向导上可以看到COM多线程模型分为这么几类:单线程(Single)、套间(Apartment)、两者(Both)、自由(Free)。这个部分个人觉得翻译不是很好,单线程(Single)个人认为翻译成单套间会比较好,原因后面有具体描述,但是作为尊重MS向导或者不至于更加把这部分弄得混乱,下面的术语还是引用MS向导上的讲法并且我尽可能使用英文术语。

可以看到COM多线程模型里最多用到的两个字是套间,那么先解释一下套间。套间可以根据他的英文想象一个房间,这个房间周围有墙,所以要进到这个房间必须用一种手段来穿透(通过门或者类似的东西),而这个房间里放的就是一个或者多个COM对象。对套间更理论性的解释是,在一个套间内存在一个或多个COM组件,而套间之间存在有一个明确的界限,并且套间内只存在唯一的一个套间线程,这个套间线程存在一个类似于消息循环(其实不应该用类似的,他就是一个隐藏了窗口的消息循环)来保证其天生所具有的同步性。看了这个定义你会觉得套间像什么?没错,一个只有一个主线程的Windows窗口应用程序进程。所以套间就是一个UI线程!做为UI线程他自然就能完成同步的功能。接下去分几个部分来讲这几种COM线程模型。

一、单线程(Single)

前面讲过这个模型最好是被翻译成单套间的好,因为这种多线程模型并不是说COM组件只能被用在单线程程序里头的,相反组件还是可以被正常的用在多线程程序里的。这种模型的真实意义是即使你的程序是多线程的并且在每个线程里都调用了CoInitalize(0,COINIT_APARTMENT),事实上在你的程序进程里头也只创建一个套间,并且把所有的组件都放到这个套间里头并由这个套间所拥有的消息循环来保证同步性。

或许这样讲不全面,但是上面一段确实讲了一种最简单的情况,就是所有的组件都按Single模型来创建。如果不是这样会什么情况呢,举个例子说A、B、C三个组件按Single模型创建,D按Apartment模型创建,并且四个组件分别在TA、TB、TC、TD四个线程里创建实例(每个线程都调用CoInitalize(0,COINIT_APARTMENT)来创建环境),那么组件A、B、C运行在由TA创建的套间里(TB、TC都没有创建套间,TA是这个套间的套间线程),而组件D则独立运行在TD创建的套间里(TD是这个套间的套间线程),这里一共就有了两个套间。这样应该是完整的情况了,再复杂的情况我想你都能推出来了。

二、套间(Apartment)

这种模型与前一种模型很相似,可以都被认为是创建WIN32概念上的UI线程,但是不同的在于,Single模型无论你在多少个线程里调用多少次CoInitalize(0,COINIT_APARTMENT)都只创建一个套间,套间的套间线程是你第一次调用CoInitalize(0,COINIT_APARTMENT)的线程,而Apartment模型则是你在一个线程上调用一个CoInitalize(0,COINIT_APARTMENT)就创建一个套间,并且把这个线程作为套间线程。

三、自由(Free)

这种模型就是工作者线程了,COM不再用消息循环来提供同步机制了。你要在多线程里使用,OK,那你自己给他做同步机制(或者由组件开发者把组件做成线程安全的)。你要单线程里使用,那更好无论如何都不需要同步了。

四、两者(Both)

这种模型保证了组件即能在套间模型使用也能在自由模型使用。例如说组件自身被创建为Apartment或者Single,但是使用者用CoInitalize(0,COINIT_MULITITHREAD)来创建环境,那么COM自己会再创建一个线程用CoInitalize(0,COINIT_APARTMENT)来创建环境供组件运行,反之亦然。

最后讲一下跨套间调用的问题,从上面的描述可以看到在Single和Apartment这两种模型里头套间内调用或者通过COM机制套间之间的通信都会被同步化,但是如何跨套间调用呢,比如说我们经常做这种事情,把一个存在在套间内组件的接口指针作为线程参数传递到另外一个线程中使用,或者两个组件存在于不同的套间中,但是由于连接点或者回调的原因需要互相调用。这个时候我们就需要使用proxy/stub机制,在传递接口指针之前调用CoMashalInterThreadInterface这个函数(我估计这个是所有WIN32API里函数名最长的函数了,MS真不让人过好日子-.-|||)来包装接口指针给PS dll来传递,然后再那个调用的线程或者套间里使用CoGetInterfaceAndReleaseStream来重新获得被调度过的接口指针,这样就能确保COM的线程同步机制能够正常的运行。

好了,全部讲完了,如果还不清楚建议去看一下《COM技术内幕》里的第十二章,这本书是我见过的所有书里对这部分描述得最好的一本(胜过《ATL技术内幕》),特别是里面那几张图,对理解这些模型非常有帮助,这书网上有电子版。

时间: 2024-10-08 05:56:14

【转载】COM的多线程模型的相关文章

第13章 TCP编程(4)_基于自定义协议的多线程模型

7. 基于自定义协议的多线程模型 (1)服务端编程 ①主线程负责调用accept与客户端连接 ②当接受客户端连接后,创建子线程来服务客户端,以处理多客户端的并发访问. ③服务端接到的客户端信息后,回显给客户端 (2)客户端编程 ①从键盘输入信息,并发送给服务端 ②接收来自服务端的信息 //msg.h与前一节相同 #ifndef __MSG_H__ #define __MSG_H__ #include <sys/types.h> //求结构体中成员变量的偏移地址 #define OFFSET(T

memcached源码阅读----使用libevent和多线程模型

本篇文章主要是我今天阅读memcached源码关于进程启动,在网络这块做了哪些事情. 一.iblievent的使用 首先我们知道,memcached是使用了iblievet作为网络框架的,而iblievet又是单线程模型的基于linux下epoll事件的异步模型.因此,其基本的思想就是 对可读,可写,超时,出错等事件进行绑定函数,等有其事件发生,对其绑定函数回调. 可以减掉了解一下 libevent基本api调用 struct event_base *base; base = event_bas

boost中asio网络库多线程并发处理实现,以及asio在多线程模型中线程的调度情况和线程安全。

1.实现多线程方法: 其实就是多个线程同时调用io_service::run for (int i = 0; i != m_nThreads; ++i)        {            boost::shared_ptr<boost::thread> pTh(new boost::thread(                boost::bind(&boost::asio::io_service::run,&m_ioService)));            m_l

[线程同步互斥]多线程模型

线程的实现方式 线程的实现可以分为两类:用户级线程(User-LevelThread, ULT)和内核级线程(Kemel-LevelThread,  KLT).内核级线程又称为内核支持的线程. 在用户级线程中,有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在.应用程序可以通过使用线程库设计成多线程程序.通常,应用程序从单线程起始,在该线程中开始运行,在其运行的任何时刻,可以通过调用线程库中的派生例程创建一个在相同进程中运行的新线程.图2-2(a)说明了用户级线程的实现方式. 在内核

Muduo 多线程模型对比

本文主要对比Muduo多线程模型方案8 和方案9 . 方案8:reactor + thread pool ,有一个线程来充当reactor 接受连接分发事件,将要处理的事件分配给thread pool中的线程,由thread pool 来完成事件处理.实例代码见:examples/sudoku/server_threadpool.cc 这里截取关键部分代码进行说明. class SudokuServer { public : SudokuServer(EventLoop* loop, const

Apache Spark探秘:多进程模型还是多线程模型?(转)

Apache Spark的高性能一定程度上取决于它采用的异步并发模型(这里指server/driver端采用的模型),这与Hadoop 2.0(包括YARN和MapReduce)是一致的.Hadoop 2.0自己实现了类似Actor的异步并发模型,实现方式是epoll+状态机,而Apache Spark则直接采用了开源软件Akka,该软件实现了Actor模型,性能非常高.尽管二者在server端采用了一致的并发模型,但在任务级别(特指Spark任务和MapReduce任务)上却采用了不同的并行机

线程的概念和多线程模型

线程的基本概念 引入进程的目的,是为了使多道程序并发执行,以提高资源利用率和系统吞吐量:而引入线程,则是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能. 线程最直接的理解就是“轻量级进程”,它是一个基本的CPU执行单元,也是程序执行流的最小单元,由线程ID.程序计数器.寄存器集合和堆栈组成.线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源.一个线程可以创建和

实际项目中Java多线程模型的总结整理

分享一下最近项目中用到的多线程模型. 需要实现:根据租户填写的表单,自动部署ES集群,提供ES服务. 基本思路: 就是将一个事务生命周期分成不同的阶段,每个阶段都是用线程去负责执行. 目前主要分为四个阶段:事件监听阶段,事件提交阶段,执行器阶段,状态校验阶段 流程图如下: 线程分类: A.监听线程 B.工作线程 C.状态校验线程 D.执行器线程 原理图简单介绍: 1.AcceptorThread线程:监听操作对列表,将新产生的事件记录扔进事件分类器,并且同时往内存容器中添加一条记录. 2.事件分

(转载)Java多线程入门理解

转载出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalangThread类 二实现javalan