ATL源码学习---线程模型支持

1.线程锁的类型

  线程锁类型有CComCriticalSection,CComAutoCriticalSection、 CComSafeDeleteCriticalSection、CComAutoDeleteCriticalSection、 CComFakeCriticalSection。每种锁都有它们的特定用途。

[c-sharp] view plain copy
// COM Sync Classes 
class CComCriticalSection  
{  
public:  
    CComCriticalSection() throw()  
    {  
        memset(&m_sec, 0, sizeof(CRITICAL_SECTION));  
    }  
    ~CComCriticalSection()  
    {  
    }  
    HRESULT Lock() throw()  
    {  
        EnterCriticalSection(&m_sec);  
 return S_OK;  
    }  
    HRESULT Unlock() throw()  
    {  
        LeaveCriticalSection(&m_sec);  
 return S_OK;  
    }  
    HRESULT Init() throw()  
    {  
        HRESULT hRes = E_FAIL;  
        __try  
        {  
            InitializeCriticalSection(&m_sec);  
            hRes = S_OK;  
        }  
 // structured exception may be raised in low memory situations 
        __except(STATUS_NO_MEMORY == GetExceptionCode())  
        {             
            hRes = E_OUTOFMEMORY;         
        }  
 return hRes;  
    }  
    HRESULT Term() throw()  
    {  
        DeleteCriticalSection(&m_sec);  
 return S_OK;  
    }     
    CRITICAL_SECTION m_sec;  
};  
class CComAutoCriticalSection : public CComCriticalSection  
{  
public:  
    CComAutoCriticalSection()  
    {  
        HRESULT hr = CComCriticalSection::Init();  
 if (FAILED(hr))  
            AtlThrow(hr);  
    }  
    ~CComAutoCriticalSection() throw()  
    {  
        CComCriticalSection::Term();  
    }  
private :  
    HRESULT Init(); // Not implemented. CComAutoCriticalSection::Init should never be called 
    HRESULT Term(); // Not implemented. CComAutoCriticalSection::Term should never be called 
};  
class CComSafeDeleteCriticalSection : public CComCriticalSection  
{  
public:  
    CComSafeDeleteCriticalSection(): m_bInitialized(false)   
    {  
    }  
    ~CComSafeDeleteCriticalSection() throw()  
    {  
 if (!m_bInitialized)  
        {  
 return;  
        }  
        m_bInitialized = false;  
        CComCriticalSection::Term();  
    }  
    HRESULT Init() throw()  
    {  
        ATLASSERT( !m_bInitialized );  
        HRESULT hr = CComCriticalSection::Init();  
 if (SUCCEEDED(hr))  
        {  
            m_bInitialized = true;  
        }  
 return hr;  
    }  
    HRESULT Term() throw()  
    {  
 if (!m_bInitialized)  
        {  
 return S_OK;  
        }  
        m_bInitialized = false;  
 return CComCriticalSection::Term();  
    }  
    HRESULT Lock()  
    {  
 // CComSafeDeleteCriticalSection::Init or CComAutoDeleteCriticalSection::Init 
 // not called or failed. 
 // m_critsec member of CComObjectRootEx is now of type  
 // CComAutoDeleteCriticalSection. It has to be initialized 
 // by calling CComObjectRootEx::_AtlInitialConstruct 
        ATLASSUME(m_bInitialized);  
 return CComCriticalSection::Lock();  
    }  
private:  
 bool m_bInitialized;  
};  
class CComAutoDeleteCriticalSection : public CComSafeDeleteCriticalSection  
{  
private:  
 // CComAutoDeleteCriticalSection::Term should never be called 
    HRESULT Term() throw();  
};  
class CComFakeCriticalSection  
{  
public:  
    HRESULT Lock() throw() { return S_OK; }  
    HRESULT Unlock() throw() { return S_OK; }  
    HRESULT Init() throw() { return S_OK; }  
    HRESULT Term() throw() { return S_OK; }  
};  

2.线程锁的封装,实现锁类型的参数化

[cpp] view plain copy
template< class TLock >  
class CComCritSecLock  
{  
public:  
    CComCritSecLock( TLock& cs, bool bInitialLock = true );  
    ~CComCritSecLock() throw();  
 HRESULT Lock() throw();  
 void Unlock() throw();  
// Implementation 
private:  
    TLock& m_cs;  
 bool m_bLocked;  
// Private to avoid accidental use 
    CComCritSecLock( const CComCritSecLock& ) throw();  
    CComCritSecLock& operator=( const CComCritSecLock& ) throw();  
};  
template< class TLock >  
inline CComCritSecLock< TLock >::CComCritSecLock( TLock& cs, bool bInitialLock ) :  
    m_cs( cs ),  
    m_bLocked( false )  
{  
 if( bInitialLock )  
    {  
 HRESULT hr;  
        hr = Lock();  
 if( FAILED( hr ) )  
        {  
            AtlThrow( hr );  
        }  
    }  
}  
template< class TLock >  
inline CComCritSecLock< TLock >::~CComCritSecLock() throw()  
{  
 if( m_bLocked )  
    {  
        Unlock();  
    }  
}  
template< class TLock >  
inline HRESULT CComCritSecLock< TLock >::Lock() throw()  
{  
 HRESULT hr;  
    ATLASSERT( !m_bLocked );  
    hr = m_cs.Lock();  
 if( FAILED( hr ) )  
    {  
 return( hr );  
    }  
    m_bLocked = true;  
 return( S_OK );  
}  
template< class TLock >  
inline void CComCritSecLock< TLock >::Unlock() throw()  
{  
    ATLASSUME( m_bLocked );  
    m_cs.Unlock();  
    m_bLocked = false;  
}  

3.ATL线程模型定义

[cpp] view plain copy
class CComMultiThreadModel  
{  
public:  
 static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);}  
 static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);}  
 typedef CComAutoCriticalSection AutoCriticalSection;  
 typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection;  
 typedef CComCriticalSection CriticalSection;  
 typedef CComMultiThreadModelNoCS ThreadModelNoCS;  
};  
class CComSingleThreadModel  
{  
public:  
 static ULONG WINAPI Increment(LPLONG p) throw() {return ++(*p);}  
 static ULONG WINAPI Decrement(LPLONG p) throw() {return --(*p);}  
 typedef CComFakeCriticalSection AutoCriticalSection;  
 typedef CComFakeCriticalSection AutoDeleteCriticalSection;  
 typedef CComFakeCriticalSection CriticalSection;  
 typedef CComSingleThreadModel ThreadModelNoCS;  
};  
class CComMultiThreadModelNoCS  
{  
public:  
 static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);}  
 static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);}  
 typedef CComFakeCriticalSection AutoCriticalSection;  
 typedef CComFakeCriticalSection AutoDeleteCriticalSection;  
 typedef CComFakeCriticalSection CriticalSection;  
 typedef CComMultiThreadModelNoCS ThreadModelNoCS;  
};  

ATL中把不同线程模型下引用计数的实作封装到同一个函数中:加法是Increment(),减法是Decrement() 。三个代表不同线程模型的类:CComSingleThreadModel、CComMultiThreadModel CComMultiThreadModelNoCS 中均实作了这两个函数。这样,我们只需要把线程模型当作模板参数传递给对象,对象就能获得正确的引用计数操作动作。

其中有3种临界区 CComCriticalSectionCComAutoCriticalSectionCComFakeCriticalSection 。每一个临界区都提供了统一的4种操作来操作临界区:Lock() Unlock() Init() Term() 。我们在程序中使用“临界区”时,只需要调用这四种操作就可以达到保护数据成员不被其他线程修改的目的。

4.服务器的默认线程模型

[cpp] view plain copy
#if defined(_ATL_SINGLE_THREADED) 
#if defined(_ATL_APARTMENT_THREADED) || defined(_ATL_FREE_THREADED) 
#pragma message ("More than one global threading model defined.") 
#endif 
 typedef CComSingleThreadModel CComObjectThreadModel;  
 typedef CComSingleThreadModel CComGlobalsThreadModel;  
#elif defined(_ATL_APARTMENT_THREADED) 
#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_FREE_THREADED) 
#pragma message ("More than one global threading model defined.") 
#endif 
 typedef CComSingleThreadModel CComObjectThreadModel;  
 typedef CComMultiThreadModel CComGlobalsThreadModel;  
#elif defined(_ATL_FREE_THREADED) 
#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_APARTMENT_THREADED) 
#pragma message ("More than one global threading model defined.") 
#endif 
 typedef CComMultiThreadModel CComObjectThreadModel;  
 typedef CComMultiThreadModel CComGlobalsThreadModel;  
#else 
#pragma message ("No global threading model defined") 
#endif 

ATL内部使用CComObjectThreadModel来保护组件内部实例数据,CComGlobalThreadModel来保护全局和静态数据。

ATL提供了 CComObjectRootEx模板类,来封装上面关于引用计数的操作以及临界区的操作。只要提供给CComObjectRootEx一个代表其线程模型的模板参数,它就能实作出InternalAddRef()、InternalRelease()以及Lock()和UnLock()四个统一的操作界面。

经过了这么多层封装,ATL 已经把AddRef()和Release()所需要的操作全部实作出来了,可是ATL还是没有迈出最后的一步——没有把这些操作整合进AddRef()和 Release(),这是因为ATL还要考虑聚合的因素。在聚合的情况下,COM对象的AddRef()和Release()操作都和独立激活时候完全不同。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端程序员的自我修养

CPython源码阅读笔记(2)

CPython 中基本的数据结构是 Object,所有的 Python 对象都可以用 PyObject * 来访问,CPython 中通过 Object 手动实...

1663
来自专栏程序员互动联盟

【答疑释惑】ascii码及转义字符的含义

我们在c/c++学习开发中经常用到它,小伙伴们你们都知道那些,是不是用到的时候着急或者不知道,为什么判断字符串结尾是'\0'呢?   我们就讲讲列列ascii...

3445
来自专栏余林丰

JVM常见垃圾回收算法

jdk1.7.0_79   众所周知,Java是一门不用程序员手动管理内存的语言,全靠JVM自动管理内存,既然是自动管理,那必然有一个垃圾内存的回收机制或者回收...

2065
来自专栏java 成神之路

JVM垃圾回收算法

29411
来自专栏SeanCheney的专栏

《Pandas Cookbook》第08章 数据清理1. 用stack清理变量值作为列名2. 用melt清理变量值作为列名3. 同时stack多组变量4. 反转stacked数据5. 分组聚合后uns

第01章 Pandas基础 第02章 DataFrame运算 第03章 数据分析入门 第04章 选取数据子集 第05章 布尔索引 第06章 索引对齐 ...

1652
来自专栏北京马哥教育

深度详解 Python yield与实现

学Python最简单的方法是什么?推荐阅读:Python开发工程师成长魔法 Python yield与实现 yield的功能类似于return,但是不同之处在于...

58612
来自专栏ml

斗地主算法

       不得不承认,算法搁置了一些时间,代码的风格下降了好多!  贴上一个曹点多多且丑的代码!  Orz...  题目要求:      编码:3表示3点 ...

1K8
来自专栏算法修养

PAT 甲级 1021 Deepest Root (并查集,树的遍历)

1021. Deepest Root (25) 时间限制 1500 ms 内存限制 65536 kB 代码长度限制 16000 B ...

3257
来自专栏菩提树下的杨过

重温delphi之控制台程序:Hello World!

这二天用c#开发ActiveX时,发现不管怎么弄,c#就是没办法生成ocx的纯正activeX控件,而且还要强迫用户安装巨大的.net framework(我只...

2218
来自专栏JAVA高级架构

图解Java 垃圾回收机制

  Java技术体系中所提倡的 自动内存管理 最终可以归结为自动化地解决了两个问题:给对象分配内存 以及 回收分配给对象的内存,而且这两个问题针对的内存区域就是...

1322

扫码关注云+社区

领取腾讯云代金券