单例模式
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();
- 分配内存;
- 调用构造器
- 将指针返回值传递给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;
};