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的朋友,最好知道自己写的每行代码意味着什么,共勉。

转载于:https://www.cnblogs.com/pugang/p/3587888.html

ATL是如何实现线程安全的引用计数和多线程控制的相关推荐

  1. Rust中的引用计数Arc与Rc

    Rc 单线程引用计数.不是线程安全的,如果需要线程间引用计数可用Arc.注意他们之间的实现区别.关键源码实现如下,重点可关注Clone和Drop的实现细节. //! Single-threaded r ...

  2. 【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )

    文章目录 一. Java 虚拟机内存模型 二. 程序计数器 ( 线程私有区 ) 三. 虚拟机栈 ( 线程私有区 ) 四. 本地方法栈 ( 线程私有区 ) 五. 方法区 ( 共享数据区 ) 1. 方法区 ...

  3. linux创建线程未定义,Linux中未定义的对p线程_CREATE的引用

    Linux中未定义的对p线程_CREATE的引用#include #include #define NUM_THREADS     5void *PrintHello(void *threadid){ ...

  4. 提高C++性能的编程技术笔记:引用计数+测试代码

    引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身.对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁.换句话说,对象不再被使用时自行销毁 ...

  5. Java引用计数与实现

    引用计数(Reference Counting)可作为内存管理办法,也是老代jvm垃圾回收策略之一,原理简单但是仍有广泛的引用,如OkHttp,netty等. 回收原理 对象在创建实例的时候会在堆内存 ...

  6. 【Java 虚拟机原理】垃圾回收算法 ( Java 虚拟机内存分区 | 垃圾回收机制 | 引用计数器算法 | 引用计数循环引用弊端 )

    文章目录 一.Java 虚拟机内存分区 二.垃圾回收机制 三.引用计数器算法 ( 无法解决循环引用问题 ) 一.Java 虚拟机内存分区 Java 虚拟机内存分区 : 所有线程共有的内存区域 : 堆 ...

  7. 【深入Cocos2d-x】探索Cocos2d-x中的内存管理-引用计数和自动释放池

    2019独角兽企业重金招聘Python工程师标准>>> #深入Cocos2d-x-探索Cocos2d-x中的内存管理-引用计数和自动释放池 ###引用计数(Reference Cou ...

  8. 浅拷贝+引用计数--写时拷贝---模拟实现string容器

    引用计数 深拷贝 多个对象共享同一份资源时,最后能够保证该资源只被释放一次 应该由哪个对象释放资源? 由最后一个使用该资源的对象去释放 怎么知道一个对象是最后一个使用该资源的对象? 给一个计数,记录使 ...

  9. JVM—引用计数和可达性分析算法(存活性判断)

    1 引用计数算法 1.1 算法思想   给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:   当引用失效时,计数器值就减1:   任何时候计数器为0时的对象就是不能再被使用. 1. ...

最新文章

  1. Redis初学:6(List类型)
  2. 如果不是为了面试,AI工程师刷题有用吗?
  3. 多线程编程1-NSThread
  4. 全国首个5G+AI的智慧交通管理示范应用成功开通!
  5. 有点烦,不知道如何开始准备评测师考试?
  6. HIbernate的检索方式
  7. 算法练习:将字符串中所有的空格替换为'%20'(只用基本数据结构)
  8. Angular ngOnChanges hook学习笔记
  9. 蓝桥杯评测_前n项和
  10. ATL中的C++模板
  11. 学习 | 雷军 1994 年写的代码,不服不行
  12. qt调用仪器驱动库dll实现程控
  13. Kuma是什么? Kuma1.0 GA 发布了包含70+新特性和改进
  14. 京东青龙面板撸豆_搭建环境流程
  15. js:使用amaze select插件
  16. html转换成pdf工具-wkhtmltopdf、Python生成PDF(pdfkit库)
  17. 异常点检测算法(三)Replicator Neural Networks
  18. 隐藏微信小程序返回首页按钮(小房子)
  19. 黑苹果忘记密码解决办法
  20. poj 1689 zoj 1422 3002 Rubbery (Geometry + BFS)

热门文章

  1. 如何做一个国产数据库(七) 网络传输 java做订阅客户端
  2. 目前阶段的任务及计划
  3. 深度学习入门:Day-11_CNN
  4. 【kafka】kafka topic某些分区 副本落后leader太多
  5. 【Elasticsearch】使用 Elasticsearch 轻松进行文本分类
  6. 【Flink】Generic types have been disabled in the ExecutionConfig and type KryoSerializer Row
  7. 【kafka】kafka 控制台 消费报错 cant rebalance afer 4 retries
  8. 【Elasticsearch】es 增加 删除 节点
  9. List 、Set、 Map有什么区别和联系
  10. 计算机原理期末考试,计算机原理期末考试题