懒汉式实现的单例模式
上文中给出的懒汉式实现的单例模式,在单线程中使用时完全没有问题的,但是在多线程中使用会存在多次对象多次创建的问题。
- 线程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 ;
}
本文讨论了懒汉式单例模式在多线程环境中的问题,即可能导致对象的多次创建。为解决此问题,介绍了双检测锁的概念,这是一种在C++中用于确保单例对象唯一创建的机制。通过在锁之外和之内各进行一次对象是否为空的检查,可以减少不必要的锁竞争,同时保证线程安全。最后,给出了修正后的懒汉单例模式代码示例。
2735

被折叠的 条评论
为什么被折叠?



