zoukankan      html  css  js  c++  java
  • 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的朋友,最好知道自己写的每行代码意味着什么,共勉。

  • 相关阅读:
    winform最大化后不遮挡任务栏
    TabControl控件重绘
    EXT gridPanel 添加图片
    好记性不如烂笔头——double
    好记性不如烂笔头——datagridview相关
    datagridview合并相同单元格
    datagridview问题
    Linux折腾记
    TSC打印机使用教程终极版
    在线直播流测试地址
  • 原文地址:https://www.cnblogs.com/pugang/p/3587888.html
Copyright © 2011-2022 走看看