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. 【必备】VSCode开发Angular的必备插件
  2. 接近开关的初步测试 : DF-11N
  3. 常用的CSS属性的英文单词总结及用法、解释
  4. 关于c语言中负数位移位操作的漫谈
  5. NYOJ_5739最大岛屿(河南省第八届acm程序设计大赛)
  6. HDU4357(数学思维题)
  7. BigDecimal总结
  8. java线程读取流的时候卡死,java – 线程中断没有结束阻塞调用输入流读取
  9. ThinkPHP6项目基操(6.数据库Db操作)
  10. 如何将Anaconda更新到想要的python版本(其实使用的是Anaconda中的切换不同环境的方法,不过步骤挺好)
  11. 平衡二叉搜索树的创建
  12. 传统 JDBC 编程详解
  13. $.getJSON()应用
  14. 人工智能的未来:杀戮还是治愈?
  15. VIVADO时序约束及STA基础
  16. mysql 备库同步_MYSQL主从库同步配置过程
  17. Solidworks常用技巧
  18. CCF 期刊、会议 推荐目录
  19. matlab统计颗粒数,一种基于Matlab的谷物颗粒计数方法
  20. 如何获取http://123123123 双斜杠后面的值?

热门文章

  1. double类型最大值_2020重新出发,JAVA入门,数据类型
  2. KubeEdge led部署
  3. Qt实践录:TCP网络调试助手
  4. iptables学习笔记:使用NAT实现简单的无线AP
  5. 用易拉罐做机器人教程_不会c4d就做不出3d设计?用ps照样可以,教程在这里
  6. 【Flink】Disconnect from JobManager responsible for
  7. 【算法】剑指 Offer 29. 顺时针打印矩阵
  8. 【ElasticSearch】 ElasticSearch 读取 流程
  9. 【ES】分布式调度系统之 Elastic-Job-Lite
  10. 【jmx】java jmx 获取 kafka topic的logStart LogEnd信息