ATL是如何實現線程安全的引用計數和多線程控制的


ATL是如何實現線程安全的引用計數和多線程控制的

正如標題所示,這是我經常被問到的一個問題,而每次我都從頭開始給人說一次,其實說來過程理解起來的確有點復雜。

我們的每一個ATL Server Object都繼承於CComObjectRootEx, 而這個類其實就是秘密最核心的地方。大家想必都知道COM技術的對象存在於套間之中,套間主要分為單線程套間和多線程套間,而套間決定了引用計數的實現方式,對於單線程套間,根本不需要保護,所以引用計數的和關鍵數據保護的實現相對簡單,而多線程套間其引用計數和數據保護實現起來就比較講究,所有數據都需要保護。

但是問題來了,我們如果都按照單線程套間的實現方式,顯然不能滿足要求,而如果完全按照多線程套間的實現方式又有些浪費。這個時候C++中的高級技巧模板技術就出場了。對於復雜的多線程實現我們可以按照一般的方式實現,而對於比較特別的單線程套間我們可以使用模板特化技術,將不必要的復雜性去掉,這樣既保證了靈活性,又降低了復雜度,同時也可以去掉不必要的數據結構。下面來看看實現代碼:

template <class ThreadModel>                                                 
class CComObjectRootEx : public CComObjectRootBase {                         
public:                                                                      
    typedef ThreadModel _ThreadModel;                                        
    typedef typename _ThreadModel::AutoCriticalSection _CritSec;             
    typedef typename _ThreadModel::AutoDeleteCriticalSection _AutoDelCritSec;
    typedef CComObjectLockT<_ThreadModel> ObjectLock;                        
                                                                             
    ~CComObjectRootEx() {}                                                   
                                                                             
    ULONG InternalAddRef() {                                                 
        ATLASSERT(m_dwRef != -1L);                                           
        return _ThreadModel::Increment(&m_dwRef);                            
    }                                                                        
    ULONG InternalRelease() {                                                
#ifdef _DEBUG                                                                
        LONG nRef = _ThreadModel::Decrement(&m_dwRef);                       
        if (nRef < -(LONG_MAX / 2)) {                                        
            ATLASSERT(0 &&                                                   
            _T("Release called on a pointer that has"                        
               " already been released"));                                   
        }                                                                    
        return nRef;                                                         
#else                                                                        
        return _ThreadModel::Decrement(&m_dwRef);                            
#endif                                                                       
    }                                                                        
                                                                             
    HRESULT _AtlInitialConstruct() { return m_critsec.Init(); }              
    void Lock() {m_critsec.Lock();}                                          
    void Unlock() {m_critsec.Unlock();}                                      
private:                                                                     
    _AutoDelCritSec m_critsec;                                               
};                                                                           
                                                                             
template <>                                                                  
class CComObjectRootEx<CComSingleThreadModel>                                
    : public CComObjectRootBase {                                            
public:                                                                      
    typedef CComSingleThreadModel _ThreadModel;                              
    typedef _ThreadModel::AutoCriticalSection _CritSec;                      
    typedef _ThreadModel::AutoDeleteCriticalSection                          
        _AutoDelCritSec;                                                     
    typedef CComObjectLockT<_ThreadModel> ObjectLock;                        
                                                                             
    ~CComObjectRootEx() {}                                                   
                                                                             
    ULONG InternalAddRef() {                                                 
        ATLASSERT(m_dwRef != -1L);                                           
        return _ThreadModel::Increment(&m_dwRef);                            
    }                                                                        
    ULONG InternalRelease() {                                                
#ifdef _DEBUG                                                                
        long nRef = _ThreadModel::Decrement(&m_dwRef);                       
        if (nRef < -(LONG_MAX / 2)) {                                        
            ATLASSERT(0 && _T("Release called on a pointer "                 
                      "that has already been released"));                    
        }                                                                    
        return nRef;                                                         
#else                                                                        
        return _ThreadModel::Decrement(&m_dwRef);                            
#endif                                                                       
    }                                                                        
                                                                             
    HRESULT _AtlInitialConstruct() { return S_OK; }                          
                                                                             
    void Lock() {}                                                           
    void Unlock() {}                                                         
};                        

 

從代碼中我們可以看出,對於特化的單線程套間實現,lock() 和unlock()是空實現,內部的critical section 成員變量也被去掉了,完全兼顧了靈活性和性能。

 

 

總結

對於Windows編程,如果不理解COM技術可能永遠也理解不了微軟在干什么,同樣,如果不懂ATL 可能就很難寫出完美的COM Server。很多人,只是寫出了可以運行的代碼,但是根本不知道自己在干什么,不出問題是不可能的,一旦出了問題,他寫的爛代碼的維護成本就會成倍增加,所以我建議用ATL 技術寫COM Server的朋友,最好知道自己寫的每行代碼意味着什么,共勉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM