c++的单例模式的一种写法以及多线程安全问题

单例模式

Code

// 单例设计模式
class sigleC {
public:
	static sigleC* getInstance() {
		if (m_instance == nullptr) {
			m_instance = new sigleC();
			static delobj cl; // 
		}
		return m_instance;	
	}
	// 通过嵌套类来实现析构
	class delobj {
	public:
		~delobj()
		{
			if (sigleC::m_instance) {
				delete sigleC::m_instance;
				sigleC::m_instance = nullptr; // 创建的单例能一直维持到程序结束才被释放
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
private:
	sigleC(){}
	static sigleC* m_instance;


};

// 类静态变量初始化
sigleC* sigleC::m_instance = nullptr;
int main()
{
	sigleC* p1 = sigleC::getInstance(); // 只创建一个sigleC类对象
	sigleC* p2 = sigleC::getInstance();

	return 0;
}

那么为什么不在单例类的析构函数中直接释放m_instance,而在类中嵌套另一个类?

原因

析构函数是在类的某一个对象离开作用域时自动调用的,如果在程序中创建了一个单例类对象obj1,之后obj1离开了它的作用域,后来我又创建了一个单例类对象obj2,期望是后来创建的obj2的内容和原来创建obj1时的m_instance是一样的。如果是在单例类的析构函数中释放m_instance然后置为null的话,则我后面obj2所得到的instance又是重新new出来的,和原来obj1的instance不是同一个!
总结:用老师的方式所,

多线程安全问题:双重锁定

#include <iostream>
#include <mutex>
using namespace std;
std::mutex resource_mutex;

class sigleC {
public:
	static sigleC* getInstance() {
		if (m_instance == nullptr) { // 双重锁定机制
			std::unique_lock<std::mutex> mymutex(resource_mutex);
			if (m_instance == nullptr) {
				m_instance = new sigleC();
				static delobj cl;
			}
		}
		return m_instance;
	}
	// 通过嵌套类来实现析构
	class delobj {
	public:
		~delobj()
		{
			if (sigleC::m_instance) {
				delete sigleC::m_instance;
				sigleC::m_instance = nullptr; // 创建的单例能一直维持到程序结束才被释放
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
private:
	sigleC() {}
	static sigleC* m_instance;
};

// 线程函数
void mythread()
{
	cout << "开辟线程开始" << endl;
	sigleC* p1 = sigleC::getInstance(); // 只创建一个sigleC类对象
	cout << "开辟线程结束" << endl;
}

// 类静态变量初始化
sigleC* sigleC::m_instance = nullptr;

int main()
{
	std::thread t1(mythread);
	std::thread t2(mythread);
	t1.join();
	t2.join();
	sigleC::getInstance()->func();
	return 0;
}

双重锁定亦然存在问题,会带来reorder现象

正常的指令序列m_instance = new sigleC();

  1. 分配内存;
  2. 调用构造器
  3. 将指针返回值传递给m_instance
    我们以为cpu会这么做,但是实际上可能会发生2、3步骤交换的情况,导致双重锁定失效

解决办法如下:

在这里插入图片描述

方法2:std::call_once()
std::mutex resource_mutex;
std::once_flag g_flag; // 这是个系统定义的标记
 
class sigleC {
public:
	static void createInstance() {  // 只被调用一次
		m_instance = new sigleC();
		static delobj cl;
	}

	static sigleC* getInstance() {
		std::call_once(g_flag, createInstance);  // 可以把g_flag想象成一把锁
		return m_instance;
	}
	// 通过嵌套类来实现析构
	class delobj {
	public:
		~delobj()
		{
			if (sigleC::m_instance) {
				delete sigleC::m_instance;
				sigleC::m_instance = nullptr; // 创建的单例能一直维持到程序结束才被释放
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
private:
	sigleC() {}
	static sigleC* m_instance;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

量子孤岛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值