ATL引用计数器的实现

COM对象必须在套间中运行。套间分为单线程套间和多线程套间。在单线程套间中,套间保证COM对象实例仅有一个线程可以访问,而在多线程套间中,COM对象实例可同时被多个线程访问。因此,在多线程套间中执行的COM对象必须解决多线程访问的同步和冲突等线程安全相关问题。

引用计数器管理的实现——CComObjectRootEx

ATL使用CComObjectRootEx类来实现对COM对象计数器的管理,因此,所有的基于ATL的COM对象必须从该类继承。CComObjectRootEx类的声明和实现如下(精简):

template< class ThreadModel >
class CComObjectRootEx : public CComObjectRootBase
{
public:
    
typedef  ThreadModel  _ThreadModel;
    ...
    
// 引用计数器m_dwRef在CComObjectRootBase中声明
    
ULONG InternalAddRef()
    
{ return _ThreadModel::Increment(&m_dwRef); }   
    
ULONG InternalRelease()
    
{ return _ThreadModel::Decrement(&m_dwRef); }
};

由上述代码可见,对于CComObjectRootEx类:
1) 实现了对引用计数器递增与递减的操作,但并未实现IUnknown接口所要求的对对象声明周期的管理,没有在计数器归零后释放对象。
2) 对于应用技术的操作依赖于模板参数ThreadModel,即该对象的线程模型,包括CComSingleThreadModel类和CComMultiThreadModel类。因此,对象访问的线程安全问题,将在这两个类中实现。

套间线程模型的实现——CComSingleThreadModel与CComMultiThreadModel

CComSingleThreadModel类和CComMultiThreadModel类的实现概要如下:

class CComSingleThreadModel
{
    
typedef CComFakeCriticalSection  AutoCritcalSection;
    
typedef CComFakeCriticalSection  CriticalSection;
    
typedef CComSingleThreadMode   ThreadModeNoCS;
 
    
static ULONG Increment(LPLONG p) { return ++(*p); }
    
static ULONG Decrement(LPLONG p) { return --(*p); }
};
 
class CComMultiThreadModel
{
    
typedef CComAutoCriticalSection    AutoCritcalSection;
    
typedef CComCriticalSection          CriticalSection;
    
typedef CComMultiThreadModeNoCs ThreadModeNoCS;
 
    
static ULONG Increment(LPLONG p)
    
{ return InterlockedIncrement(p); }
    
static ULONG Decrement(LPLONG p)
    
{ return InterlockedDecrement(p); }
};

CComSingleThreadModel与CComMultiThreadModel具有相同的结构和方法声明,只是在实现计数器递增或递减的时候,CComMultiThreadModel采用了线程安全的API函数而ComSingleThreadModel。并且,CComMultiThreadModel声明了真实的临界区对象类型(CComAutoCriticalSection和CComCriticalSection ),供其他需要线程同步的操作使用。CComSingleThreadModel仅仅为保持与CComMultiThreadModel具有相同的结构而声明了两个伪装的临界区类型(CComFakeCriticalSection)。CComFakeCriticalSection是伪装的临界区类,其中并没有提供真实的临界区,而仅仅声明了与CComAutoCriticalSection和CComCriticalSection相同的方法。

结论

为了对单线程套间对象与多线程套间对象的引用计数实现一个统一的访问控制模型,ATL将COM的引用计数器管理的实现从IUnknown接口所定义的对象生命周期管理中抽出,并在CComObjectRootEx类中单独实现。CComObjectRootEx通过模板参数指定对象所使用的线程模型。在CComMultiThreadModel中声明和实现了线程安全的方法。由此,任何ATL COM对象必须继承自CComObjectRootEx来实现引用计数,并在继承时指定线程模型。

Leave a comment

Please be polite and on topic. Your e-mail will never be published.