使用 InterlockedIncrement/InterlockedDecrement 的一个误区 .
class MObj
{
long m_refCount ;
public:
MObj(){ m_refCount = 1 ; }
long AddRef(){InterlockedIncrement(&m_refCount); return m_refCount ; }
long Release(){ InterlockedDecrement(&m_refCount); if( refCount ==0 ) delete this ; return m_refCount ;}
};
InterlockedIncrement,InterlockedDecrement 都是保证整型变量自增,自减的原子性,所以上面的代码似乎没什么问题,但在实现使用中,程序运行一段时间后就会出现Bug,调试进去都是停在Release()的 delete this 这里出问题,而且看一下这个对象的数据,发现好像已经析构了两次,十分费解,难道第一次析构后 m_refCount 值随机赋与了1,这样也太不安全了吧,所以便查看了一下MFC的COM对象的Release函数的实现,MS的代码是这样的:
long result = InterlockedDecrement(&m_refCount); if( result==0 ) delete this ;
这样和我原来的有区别吗? MS的只是通过那InterlockedDecrement返回的值作判断,但返回的值应该是等于 m_refCount 才是的. 于是我把MS的代码拷贝到我的代码去,程序运行很久也不会出现Bug了,奇怪了,于是再想一下,终于发现问题了,假如如果有两个线程现在调用Release函数,顺序是这样的:
1,线程A: InterlockedDecrement(&m_refCount); if( refCount ==0 ) delete this ; // m_refCount = 1
2,线程B: InterlockedDecrement(&m_refCount); if( refCount ==0 ) delete this ; // m_refCount = 0
这样是没问题的,如果是下面的顺序就会出问题:
1, 线程A: InterlockedDecrement(&m_refCount); // m_refCount = 1
2, 线程B: InterlockedDecrement(&m_refCount); // m_refCount = 0
3, 线程A: if( refCount ==0 ) delete this ;// m_refCount = 0 所以会调用 delete this
4, 线程B: if( refCount ==0 ) delete this ;// m_refCount = 0 所以会再次调用 delete this , 出错
所以MS的做法是对,直接判断返回值,因为返回值就是原子性自减后的结果.
在网上搜了一下,发现不少我这样做法的代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)