应用场景:在整个系统中只能有一个实例对象
1 class Singleton 2 { 3 private: 4 Singleton(); 5 ~Singleton(); 6 Singleton(const Singleton&); 7 Singleton&operator=(const Singleton&); 8 public: 9 static Singleton *getinstance(); 10 static Singleton *m_instance; 11 } 12 Singleton *Singleton::m_instance=NULL;
case1:单线程,此时不会出现线程安全问题
1 Singleton *Singleton::getinstance() 2 { 3 if(m_instance==NULL) 4 { 5 m_instance=new Singleton(); 6 } 7 return m_instance; 8 }
case2:多线程
1 //线程安全,但是锁的代价高 2 Singleton *Singleton::getinstance() 3 { 4 Lock lock; 5 if(m_instance==NULL) 6 { 7 m_instance=new Singleton(); 8 } 9 return m_instance; 10 }
如果多个线程只是读操作,会影响效率
改进版,双检查锁
Singleton* Singleton::getinstance() { if(m_instance==NULL) //避免都是读操作时加锁,代价过高 { Lock lock; if(m_instance==NULL) //这行不能省,如果省略,会出现多个实例 m_instance=new Singleton(); } return m_instance; }
这个双检查锁版本看似完美,但是还有漏洞。
m_instane=new Singleton();被编译器拆分成三个动作:step1、调用malloc分配空间;step2、m_instance指针指向新分配好的空间,step3、调用构造函数初始化。如果线程1在执行到第二步以后,线程2进入函数开始判断m_instance是否为空,发现不为空,立即返回m_instance,但是此时m_instance并没有初始化完成。由此可见双检查锁欺骗了线程2。