使用 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 @ 2012-03-04 03:16  therockthe  阅读(1579)  评论(0)    收藏  举报