C++的双重检查锁并不安全(转)
一个典型的单例模式构建对象的双重检查锁如下:
1 static Singleton * getSingleObject() 2 { 3 if(singleObject==NULL) 4 { 5 lock(); 6 if(singleObject==NULL) 7 { 8 singleObject = new Singleton(); 9 } 10 unlock(); 11 } 12 return singleObject; 13 }
该代码的逻辑是:getSingleObject()函数获得对象,如果对象不存在则创建,反之则直接返回。考虑到线程安全,创建对象时需要加锁(否则可能多线程同时调用该函数时创建多个对象)。同时为了避免线程每次调用getSingleObject()函数时候都要被锁住等待,减小线程间的开销,使用双重检查锁,即只有对象不存在时才锁住等待。
看起来天衣无缝……
C++在new一个对象时,首先会把指针指向分配的那块空间,然后在初始化该空间。
这样假设线程A执行到new该对象时,分配了指针,但是还未来得及构建那块空间。此时线程B执行getSingleObject()函数,由于指针已经分配所以直接返回该地址(但其实是一块还未初始化的地址),线程B操作该地址,game over。。
一种解决方法,但还是有可能出错:
1 class Singleton { 2 public: 3 static volatile Singleton* volatile instance(); 4 ... 5 private: 6 // one more volatile added 加入另一个volatile声明 7 static volatile Singleton* volatile pInstance; 8 }; 9 // from the implementation file 实现文件内容如下 10 volatile Singleton* volatile Singleton::pInstance = 0; 11 volatile Singleton* volatile Singleton::instance() { 12 if (pInstance == 0) { 13 Lock lock; 14 if (pInstance == 0) { 15 // one more volatile added 加入另一个volatile声明 16 volatile Singleton* volatile temp = 17 new volatile Singleton; 18 pInstance = temp; 19 } 20 } 21 return pInstance; 22 }
联系方式:emhhbmdfbGlhbmcxOTkxQDEyNi5jb20=