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的朋友,最好知道自己写的每行代码意味着什么,共勉。
转载于:https://www.cnblogs.com/pugang/p/3587888.html
ATL是如何实现线程安全的引用计数和多线程控制的相关推荐
- Rust中的引用计数Arc与Rc
Rc 单线程引用计数.不是线程安全的,如果需要线程间引用计数可用Arc.注意他们之间的实现区别.关键源码实现如下,重点可关注Clone和Drop的实现细节. //! Single-threaded r ...
- 【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )
文章目录 一. Java 虚拟机内存模型 二. 程序计数器 ( 线程私有区 ) 三. 虚拟机栈 ( 线程私有区 ) 四. 本地方法栈 ( 线程私有区 ) 五. 方法区 ( 共享数据区 ) 1. 方法区 ...
- linux创建线程未定义,Linux中未定义的对p线程_CREATE的引用
Linux中未定义的对p线程_CREATE的引用#include #include #define NUM_THREADS 5void *PrintHello(void *threadid){ ...
- 提高C++性能的编程技术笔记:引用计数+测试代码
引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身.对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁.换句话说,对象不再被使用时自行销毁 ...
- Java引用计数与实现
引用计数(Reference Counting)可作为内存管理办法,也是老代jvm垃圾回收策略之一,原理简单但是仍有广泛的引用,如OkHttp,netty等. 回收原理 对象在创建实例的时候会在堆内存 ...
- 【Java 虚拟机原理】垃圾回收算法 ( Java 虚拟机内存分区 | 垃圾回收机制 | 引用计数器算法 | 引用计数循环引用弊端 )
文章目录 一.Java 虚拟机内存分区 二.垃圾回收机制 三.引用计数器算法 ( 无法解决循环引用问题 ) 一.Java 虚拟机内存分区 Java 虚拟机内存分区 : 所有线程共有的内存区域 : 堆 ...
- 【深入Cocos2d-x】探索Cocos2d-x中的内存管理-引用计数和自动释放池
2019独角兽企业重金招聘Python工程师标准>>> #深入Cocos2d-x-探索Cocos2d-x中的内存管理-引用计数和自动释放池 ###引用计数(Reference Cou ...
- 浅拷贝+引用计数--写时拷贝---模拟实现string容器
引用计数 深拷贝 多个对象共享同一份资源时,最后能够保证该资源只被释放一次 应该由哪个对象释放资源? 由最后一个使用该资源的对象去释放 怎么知道一个对象是最后一个使用该资源的对象? 给一个计数,记录使 ...
- JVM—引用计数和可达性分析算法(存活性判断)
1 引用计数算法 1.1 算法思想 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1: 当引用失效时,计数器值就减1: 任何时候计数器为0时的对象就是不能再被使用. 1. ...
最新文章
- 【必备】VSCode开发Angular的必备插件
- 接近开关的初步测试 : DF-11N
- 常用的CSS属性的英文单词总结及用法、解释
- 关于c语言中负数位移位操作的漫谈
- NYOJ_5739最大岛屿(河南省第八届acm程序设计大赛)
- HDU4357(数学思维题)
- BigDecimal总结
- java线程读取流的时候卡死,java – 线程中断没有结束阻塞调用输入流读取
- ThinkPHP6项目基操(6.数据库Db操作)
- 如何将Anaconda更新到想要的python版本(其实使用的是Anaconda中的切换不同环境的方法,不过步骤挺好)
- 平衡二叉搜索树的创建
- 传统 JDBC 编程详解
- $.getJSON()应用
- 人工智能的未来:杀戮还是治愈?
- VIVADO时序约束及STA基础
- mysql 备库同步_MYSQL主从库同步配置过程
- Solidworks常用技巧
- CCF 期刊、会议 推荐目录
- matlab统计颗粒数,一种基于Matlab的谷物颗粒计数方法
- 如何获取http://123123123 双斜杠后面的值?
热门文章
- double类型最大值_2020重新出发,JAVA入门,数据类型
- KubeEdge led部署
- Qt实践录:TCP网络调试助手
- iptables学习笔记:使用NAT实现简单的无线AP
- 用易拉罐做机器人教程_不会c4d就做不出3d设计?用ps照样可以,教程在这里
- 【Flink】Disconnect from JobManager responsible for
- 【算法】剑指 Offer 29. 顺时针打印矩阵
- 【ElasticSearch】 ElasticSearch 读取 流程
- 【ES】分布式调度系统之 Elastic-Job-Lite
- 【jmx】java jmx 获取 kafka topic的logStart LogEnd信息