2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 单例模式及多线程安全(C++版)

单例模式及多线程安全(C++版)

时间:2023-11-12 15:10:08

相关推荐

单例模式及多线程安全(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();

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。