单例模式

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

单例模式及多线程安全(C++版)相关推荐

  1. 单例模式在多线程中的安全性研究

    概述 关于一般单例模式的创建和分析在我的另一篇博客<Java设计模式--单件模式>中有详细说明.只是在上篇博客中的单例是针对于单线程的操作,而对于多线程却并不适用,本文就从单例模式与多线程 ...

  2. 设计模式---单例模式(多线程下的单例模式)

    1>单例类 package com.test.sigleton;public class SingletonTest {public static int num=0;//用于记录该类被实例化的 ...

  3. Java多线程之单例模式在多线程环境下的安全问题

    Java多线程之单例模式在多线程环境下的安全问题 目录: 单例模式基本概念 单线程下的单例模式 多线程下的单例模式 单例模式volatile分析 1. 单例模式基本概念 基本概念转载自:单例模式|菜鸟 ...

  4. c# 多线程单例模式_单例模式,多线程单例,双重锁定单例,工场单例创建上下文...

    单例模式,多线程单例,双重锁定单例,工厂单例创建上下文. 单例子模式定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个 ...

  5. java 多线程的单例模式,Java多线程中的单例模式两种实现方式

    Java多线程中的单例模式 一.在多线程环境下创建单例 方式一: package com.ietree.multithread.sync; public class Singletion { priv ...

  6. C++单例模式:单例模式遇到多线程

    单例模式介绍 单例模式主要有2中形式,一种是饿汉式,一种是懒汉式. 饿汉式:程序一加载单例模式就已经创建了,也就很饥饿嘛.因为是静态属性进行单例初始化,所以优点是线程是安全的,缺点是无论用户是否使用单 ...

  7. 单例模式,自定义cell加长版,对控件的圆润度设置还有另一种跳界面方式(很多界面)

    今天师兄回来教了我们很多东西,包括帮我巩固的单例模式,自定义cell的那种lol盒子的cell加长版,对控件的圆润度设置还有另一种跳界面方式. 1.单例模式:在.h的文件里面设置 1.@propert ...

  8. python 单例模式 redis_python 单例模式实现多线程共享连接池

    我们经常使用数据库连接池,但那是有时候有些库并没有实现线程安全的连接池,这个时候,该如何自己封装?多进程和多线程甚至协程模式下,如何控制数据库连接数量或者是socket连接数.这个问题很有意义.

  9. Python多线程笔记——简单函数版和类实现版

    简单函数版 import threadingdef func():while True:bodydef main():A = threading.Thread(target=func)A.daemon ...

最新文章

  1. Python 工程管理及 virtualenv 的迁移
  2. nginx+tomcat实现Windows系统下的负载均衡搭建教程
  3. ERROR: No matching distribution found for onnxsim
  4. Winform中自定义添加ZedGraph右键实现设置所有Y轴刻度的上下限
  5. HipChat上传文件报未知错误解决方案
  6. PHP陈明忠_《PHP网站开发案例教程》习题答案
  7. mysql 分组查询原理,MySQL分組查詢Group By實現原理詳解
  8. 贝叶斯判别分析的基本步骤_贝叶斯分析助你成为优秀的调参侠(1)
  9. ajax beforeSend中无效果
  10. logstash采集中文乱码
  11. 64位驱动 hp630打印机_HP LaserJet1010 打印机驱动win7 64位
  12. Eclipse下载、安装、配置教程
  13. 从阿里云迁移域名至 Amazon Route 53 帮你了解域名迁移
  14. 读后感__局外人_知其不可而为之
  15. 应用宝上架审核要求_应用宝应用市场APP上架首发申请
  16. 从父组件中获取子组件的值
  17. Tecplot中自定义函数
  18. 室内地图导航系统基础功能与衍生服务详解
  19. esc键退出全屏 vue_解决了VUE在浏览器全屏下监听不到Esc键盘事件
  20. 计算机防火墙无法关闭,为什么我电脑的防火墙关不了(win7电脑防火墙怎么关)

热门文章

  1. 一道『easy』等级的力扣题,我写了两个小时的笔记...
  2. 不使用border-radius,实现一个可复用的高度和宽度都自适应的圆角矩形
  3. 初级篇第三期:初识UI
  4. 【AdaBoost算法】积分图代码实现
  5. hdu5106 小于x的数(二进制1确定的数)的和 数位dp(first mine)
  6. github 改善网速
  7. java窗体程序秒表,帮忙解释一个Java小程序(秒表)
  8. 体现临床实际基线疾病活动度的早期RA患者中, 治疗起效时间对临床和放射学的影响...
  9. idea中启动tomcat,控制台中文乱码问题解决方案
  10. kindeditor php配置,KindEditor-编辑器配置参数属性 | 小灰灰博客