使用 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 ;}

       };

 

       InterlockedIncrementInterlockedDecrement 都是保证整型变量自增,自减的原子性,所以上面的代码似乎没什么问题,但在实现使用中,程序运行一段时间后就会出现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的做法是对,直接判断返回值,因为返回值就是原子性自减后的结果.

   在网上搜了一下,发现不少我这样做法的代码

posted @   therockthe  阅读(1559)  评论(0编辑  收藏  举报
编辑推荐:
· 基于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)
点击右上角即可分享
微信分享提示