懒汉式实现的单例模式 上文中给出的懒汉式实现的单例模式,在单线程中使用时完全没有问题的,但是在多线程中使用会存在多次对象多次创建的问题。
线程A进入getInstance方法,并进入到if判断,因为现在m_psl是空指针,这时刚好线程A时间片用完,开始切换到线程B,线程B也调用getInstance方法创建了一个对象线程B时间片用完,切换到线程A,这时线程A从if判断成功之后的下不开始,又创建了一遍对象,这时已经两次创建对象了为了解决这个问题需要使用双检测,详情可参考 C++ and the Perils of Double-Checked Locking 里面详细说明了双重检测的方法,和最终的解决方案。
要想解决上述懒汉单例模式中的问题,需要引入这个双重检测的功能,实现也只需将图中的代码在加锁的基础上,在添加一层检测 临界区(Critical Section)。临界区对象通过提供一个进程内所有线程必须 共享的对象来控制线程。只有拥有那个对象的线程可以访问保护资源。在另一个线 程可以访问该资源之前,前一个线程必须释放临界区对象,以便新的线程可以索取对象的访问权
最终实现效果如下
if (m_psl == NULL) { // 这里线程开始资源竞争,只有一个线程能获取lock的资源 lock(); if (m_psl == NULL) { m_psl = new Singelton; } unlock(); }说明: lock里面判断一次,因为可能有多个线程在lock处等待,一个成功之后,会将m_psl设置为非空,这样下个线程就算拿到lock资源,再进去发现指针非空就离开了 lock外判断一次,是因为获取锁,是很浪费时间的,获取锁之外还有一层判断,那么在第二次获取单例对象的时候,lock外的if判断发现指针已经非空,就不会再获取锁了,直接返回了对应的对象,这样双层检测,即保证了对象创建的唯一性,又减少了获取锁浪费的时间和资源
不安全的单例模式代码:
#include <iostream> using namespace std; //懒汉式 class Singelton { private: Singelton() { cout << "Singelton 构造函数执行" << endl; } public: static Singelton *getInstance() { if (m_psl == NULL) { m_psl = new Singelton; } return m_psl; } static void FreeInstance() { if (m_psl != NULL) { delete m_psl; m_psl = NULL; } } private: static Singelton *m_psl; }; Singelton *Singelton::m_psl = NULL; void main041() { Singelton *p1 = Singelton::getInstance(); Singelton *p2 = Singelton::getInstance(); if (p1 == p2) { cout << "是同一个对象" << endl; } else { cout << "不是同一个对象" << endl; } Singelton::FreeInstance(); return ; }