c++中的 单例模式(singleton)和双检测锁(Double-Checked Locking)

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

懒汉式实现的单例模式
上文中给出的懒汉式实现的单例模式,在单线程中使用时完全没有问题的,但是在多线程中使用会存在多次对象多次创建的问题。

  1. 线程A进入getInstance方法,并进入到if判断,因为现在m_psl是空指针,这时刚好线程A时间片用完,开始切换到线程B,线程B也调用getInstance方法创建了一个对象
  2. 线程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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Achilles.Wang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值