COM Apartment (套间)
来源:互联网 发布:python编译器 安卓 编辑:程序博客网 时间:2024/06/11 22:32
COM Apartment (套间)
套间的由来
COM库的规定
- COM库提供两种套间,单线程套间(STA, Single-Threaded Apartment) 和多线程套间(MTA, Multi-Threaded Apartment), COM组件的编写者最好提供对应的属性(线程模型属性, 后面会提到),COM组件的使用者要在套间里创建和调用组件。
- COM库对所有的调用进行参数调整(如果需要),不管是对进程内服务器的调用,还是对进程外服务器的调用。
- 线程内调用、跨线程调用、跨进程调用都用统一的方式。需要用代理/存根的会用代理/存根。
- 每个使用COM的进程都有一个或多个套间;
- 一个套间只能包含在某一个进程中;
- 每个套间可以拥有一个(STA)或多个(MTA)线程;
- 一个线程只在某一个套间中执行;
- 每个套间可以包含多个对象。
STA套间原则:一个进程可以包含0个,1个或者多个STA;每个STA中有且只有一个线程执行;
以上原则决定,驻留在STA中的对象永远也不能被多个线程并发访问,而且只有一个特定的线程可以执行对象的方法。
MTA套间原则:一个进程可以包含0个或者1个MTA;每个MTA中可以有多个线程执行;
以上原则决定,驻留在MTA中对象能够被多个线程并发访问,这在某些情况下可以提供程序的效率,但是作为实现者,你必须处理好线程之间的同步关系。
进程内的主STA套间是进程中第一个调用CoInitialize的线程(主线程)所关联的套间(即进程中的第一个STA套间)。主STA与STA唯一的不同是这是傻瓜型的,连静态和全局变量都可以不用线程保护,因为所有不是安全访问静态和全局变量的对象都通过主线程(第一个调用CoInitialize的线程)的消息派送机制运行,因此不安全的访问都被集中到了一个线程的调用中,因而调用被序列化了,也就实现了对静态和全局变量的线程保护。至于为什么是主线程,因为进程要使用STA,则一定会创建主线程,所以一定可以创建主STA。因此主STA并不是什么第四种套间,只是一个STA套间,不过关联的是主线程而已,由于它可以被用作保护静态和全局变量而被单独提出来说明。因此一个进程内也只有一个主STA套间。
线程分配套间的规则:
如果线程调用CoInitialize,则COM创建新的STA并且将线程放入其中如果线程调用CoInitializeEx并且传递参数COINIT_APARTMENTTHREADED,则COM创建新的STA并且将线程放入其中
如果线程调用CoInitializeEx并且传递参数COINIT_MULTITHREADED,则COM如果没有MTA,创建新的MTA并且将线程放入其中;如果存在MTA,直接将线程放入其中。
COM对象分配套间的规则:
调用CoCreateInstance或CoGetClassObject等创建对象的函数时,创建的对象将以一个特定规则决定和哪个套间相关联。
决定对象去向的规则如下:当是进程内组件时,根据COM组件注册表项<CLSID>\InprocServer32\ThreadingModel和线程所属套间的不同,列于下表:
所关联的套间种类COM组件的线程模型属性
(ThreadingModel键值)组件对象最后所在套间1STA""或Single进程内的主STA套间2STAApartment创建线程的套间3STABoth创建线程的套间4STAFree进程内的MTA套间5STA""或Single进程内的主STA套间6STAApartment新建的一个STA套间7STABoth进程内的MTA套间8STAFree进程内的MTA套间
跨套间调用需要汇集操作也就是列集→传输→散集
所有线程模型的算法都是通过代理对象实现的。要跨套间时,使用CoMarshalInterface将代理对象的CLSID和其与组件对象建立联系的一些必要信息(如组件对象的接口指针)列集(Marshaling)到一个IStream*中,再通过任何线程间通信手段(如全局变量等)将IStream*传到要使用的线程中,再用CoUnmarshalInterface散集(Unmarshaling)出接口以获得指向代理对象的接口指针。
套间实现规则
STA 当一个组件是STA时,它必须同步保护全局变量和静态变量,即对全局变量和静态变量的访问应该用临界段或其他同步手段保护,因为操作全局和静态变量的代码可以被多个STA线程同时执行,所以那些代码的地方要进行保护。比如对象计数(注意,不是引用计数),代表当前组件生成的对象个数,当减为零时,组件被卸载。此变量一般被类厂对象使用,还好ATL和MFC已经帮我们实现了缺省类厂,这里一般不用担心,但自定义的全局或静态变量得自己处理。
对象之间数据共享通常有三种方式:DLL中声明全局变量;C++类中的静态成员变量;静态局部变量
MTA 必须对组件中的每个成员和全局及静态变量的访问使用同步手段进行保护,还应考虑线程问题,即不是简单地保护访问即可,还应注意线程导致的错误的操作。
NOTE
有3个STA套间,STA1、STA2和STA3。STA1用CoMarshallInterface得到的IStream*传到STA2中通过CoUnmarshalInterface得到的代理和在STA3中同样通过CoUnmarshalInterface得到的代理不同,不能混用。因为当STA2和STA3调用在STA1的对象时,STA1如果回调(连接点技术就是一种回调)调用者,则STA2和STA3的代理能分别正确的指出需要让哪个线程执行回调操作,即向哪个线程发送消息,因此不能混用。
编写可以工作的COM客户端
规则1:客户线程必须调用CoInitialize[Ex]
规则2:STA线程需要消息循环
规则3:不要在套间之间传递原始未列集的接口指针
有没有不列集需要与其他线程共享的接口指针也OK的情况?有。如果两个线程属于同一个套间,则可以共享原始未列集的接口指针,而这只可能在两个线程都属于MTA时发生。如果不确定是否需要,请进行列集。调用CoMarshalInterThreadInterfaceInStream和CoGetInterfaceAndReleaseStream或者使用GIT总是无害的,因为COM只在必要的时候才进行列集。
- com之套间(Apartment)
- COM Apartment (套间)
- 关于COM及套间(Apartment)知识
- COM套间
- com套间
- com套间
- COM套间
- COM套间
- COM套间
- COM套间
- COM的Apartment概念
- 理解 COM 套间
- 理解COM套间
- 理解 COM 套间
- COM——套间
- 理解 COM 套间
- com之套间
- 理解 COM 套间
- 《深入理解计算机系统》读书笔记
- QTP错误处理机制
- 代码走读的重要性
- tyvj-1029 字符串
- 为了自己的光辉前途奋斗了!
- COM Apartment (套间)
- 那些岁月和贫穷无关
- C++使用C代码
- poj 2586 Y2K Accounting Bug
- 了解数据库
- ubuntu下设置VPN连接
- 面向对象(一)
- 《乔布斯传》圈点(2)
- 让窗口捕获并响应WM_MOUSEHOVER和WM_MOUSELEAVE消息