0
点赞
收藏
分享

微信扫一扫

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步骤交换的情况,导致双重锁定失效

解决办法如下:

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

方法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;
};


举报

相关推荐

0 条评论