C++并发与多线程(13) | 单例设计模式Ⅱ

单例设计模式共享数据问题分析、解决    推荐在主线程中,在创建其他线程之前就把单例对象创建了,并把其所需的数据进行装载。后续多线程也只读,这样就比较安全。

但是面临的问题:需要在我们自己创建的线程(而不是主线程)中来创建MyCAS这个单例类的对象,而且这种线程可能不止1个。

写一个测试的代码,延续之前的单例类:

// 线程入口函数voidmythread(){cout << "我的线程开始执行了" << endl; MyCAS* p_a = MyCAS::GetInstance();

cout << "我的线程结束了" << endl;return;}

intmain(){std::thread mytobj1(mythread);std::thread mytobj2(mythread); mytobj1.join(); mytobj2.join();

return0;}    这里的两个线程都创建了单例类对象。

虽然两个线程都是同一个入口函数,所以这里会有两个通路同时创建单例类对象。--这里就可能出现一个临界的情况:第一个线程已经判断未创建对象而准备(还没有)创建对象的时候,另一个线程也通过了"未创建类对象"的判断并即将创建这个对象,那么就会有两个线程同时创建类对象,那么就会发生"不是单例"的情况了。

那么如果利用互斥量来加锁呢?

static MyCAS* GetInstance(){std::unique_lock<std::mutex> mymutex(resource_mutex); // 自动加解锁

// 保证了对象只能有一个if (m_instance == NULL) { m_instance = new MyCAS();static CGarhuishou cl; }

return m_instance;}    这样写 效率比较低。因为实际上这个互斥量只有第一次创建单例类对象的时候需要,其他时候再用就会浪费时间,影响效率。

所以需要改进。

static MyCAS* GetInstance(){if (m_instance == NULL) // 双重检查 {std::unique_lock<std::mutex> mymutex(resource_mutex); // 自动加解锁

// 保证了对象只能有一个if (m_instance == NULL) { m_instance = new MyCAS();static CGarhuishou cl; } }

return m_instance;}★ 这里就是加了一个双重检查。

1)如果if(m_instance != NULL) 条件成立,则表示m_instance已经被new过了;

2)如果if(m_instance == NULL)不代表m_instance一定没被new过(之前提到的临界情况)

std::call_once()    这是C++11引入的函数,该函数的第二个参数是一个函数名a()

call_once功能是能够保证函数a()只被调用一次。

call_once()具备互斥量这种能力,而且效率上,比互斥量消耗的资源更少。

call_once()需要与一个标记结合使用,这个标记std::once_flag;其实once_flag是一个结构。

call_once()就是通过这个标记来决定对应的函数a()是否执行,调用call_once()成功后,call_once()就把这个标记设置为一种已调用状态,后续再次调用call_once(),只要once_flag被设置未来"已调用"状态,那么对应的函数a()就不会再被执行了。

所以修改之前使用互斥量的方法:

#include<iostream>#include<thread>#include<vector>#include<list>#include<mutex>usingnamespacestd;//std::mutex resource_mutex;std::once_flag g_flag; // 这是个系统定义的标记classMyCAS // 单例类{staticvoidCreateInstance()// 只被调用一次{std::chrono::milliseconds dura(20000);std::this_thread::sleep_for(dura); m_instance = new MyCAS();static CGarhuishou cl; }private: MyCAS(){} // 私有化构造函数private:static MyCAS* m_instance;// 静态成员变量public:static MyCAS* GetInstance(){// 两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕CreateInstancestd::call_once(g_flag, CreateInstance); cout << "call_once()执行完毕" << endl;return m_instance; }classCGarhuishou // 类中套类,用来释放对象 {public: ~CGarhuishou() // 析构函数里完成内存释放 {if (MyCAS::m_instance) {delete MyCAS::m_instance; MyCAS::m_instance = NULL; } } };voidfunc(){cout << "test" << endl; }};// 类静态变量初始化MyCAS* MyCAS::m_instance = NULL;// 线程入口函数voidmythread(){cout << "我的线程开始执行了" << endl; MyCAS* p_a = MyCAS::GetInstance();cout << "我的线程结束了" << endl;return;}intmain(){std::thread mytobj1(mythread);std::thread mytobj2(mythread); mytobj1.join(); mytobj2.join();return0;}    查看效果,这里只等了一次20s,说明CreateInstance只执行了一次:

「点点赞赏,手留余香」

赞赏

  • nidayesun
  • 1人赞过
1
0
0
评论 0 请文明上网,理性发言

相关文章

  • 作者|BartlomiejFilipek译者|王强策划|万佳C++发展得非常快!例如,C++标准的页数从C++98/03的879页增加到了C++20的1834页,多了近1000页!更重要的是,C++每次修订后,我们都会获得几十个新特性。你需要学习所有这些东西才能写出好代码吗?如何在当今的C++世界中保持理智? 介绍你可
    YFLeslie 6 1 0 条评论
  • 作者|我不想种地 责编|屠敏 封图|CSDN付费下载自东方IC 引言 团队有项目考虑用Go重写,所以花了些时间调研Go。 第一次接触Go是5年前,14年4月份,也是在我司,全职钻研一周,彼时C++中毒太深,内心排斥其他编程语言,看其他语法总觉得有点怪,而且有"C/C++能做任何事,故无用其他语言之必要"的思想在作祟。
    glzt 8 4 0 条评论
  • 作者|繁星蓝雨责编|夕颜头图|CSDN下载自视觉中国 出品|CSDN(ID:CSDNnews) 常见观点 可以轻易的找出许多文献说明C++太复杂了,例如学习C++的书籍的厚度。 这样以至于C++的设计者Bjarne都曾怀疑具有类的C是不是已经太庞大了。 因为,总有大量对语言的新特性的要求: 对如何利用现有特性完成某些
    謫nY 4 6 0 条评论
  • 编辑|Lisa C++20要来了!然而,大家都不看好是怎么回事儿? 为了C++20,C++标准委员会曾举办历史上规模最大的一次会议(180人参会),试图通过会议确定哪些特性可以加入新版本,我们也已经看到媒体爆料的部分新特性,比如Concepts、Ranges、Modules、Coroutimes等,但大部分开发人员并
    SIRISGODLIKE11 4 0 0 条评论
  • 作者|OwenHughes 译者|Sambodhi 策划|刘燕 强大、灵活、复杂:C++的起源可以追溯到40年前,但它仍然是当今使用最广泛的编程语言之一。为了找出原因,TechRepublic采访了C++之父BjarneStroustrup。 C++的起源可以追溯到1979年,那时编程语言的创造者BjarneStr
    帝丿紅錧 8 4 0 条评论
  • 作者|Amazing10来源|业余码农(ID:Amateur_coder)头图|CSDN下载自东方IC看到标题,你可能不太明白是什么意思。不要着急,看到最后你就明白啦。我相信很多人接触编程都是源于大学期间的那堂C++语言程序编程,但是这门课却只告诉了你编程语言是什么,却没告诉你要怎么去熟练掌握编程。所以,不可避免的是
    打死-小袋狗 4 3 0 条评论
  • 选自modernescpp 作者:JPTech等 机器之心编译 参与:Panda、杜伟C++20(C++编程语言标准2020版)将是C++语言一次非常重大的更新,将为这门语言引入大量新特性。近日,C++开发者RainerGrimm正通过一系列博客文章介绍C++20的新特性。目前这个系列文章已经更新了两篇,本篇是第一篇,
    大傻帽活宝 3 1 0 条评论
  • 刚刚结束的C++标准委员会2019春季会议在夏威夷科纳举办,委员会在这次会议中确定了下一个国际标准C++20的全部特性,这标志着C++20的特性设计工作已完成。 按照C++20的发布计划,这次会议正是为了冻结C++20的特性而举办,进入特性冻结阶段(Featurefreeze)意味着所有的功能特性将被冻结,并且不会再加
    931v 4 3 0 条评论
  • 关键时刻,第一时间送达! 何为C++17? C++17是继C++14之后,C++编程语言ISO/IEC标准的下一次修订的非正式名称。而就在昨日,ISOC++委员会正式发布了C++17标准,官方名称为ISO/IEC14882:2017。 C++17标准化图表 C++17主要特性 基于C++11,C++17旨在使C++成
    Hancartoon 3 0 0 条评论
  • 现在日常生活和工作中用到的很多软件都是使用MicrosoftVisualStudio编写的,这类软件想要在Windows中运行是少不了微软系统运行库的,例如Adobe系列软件、常用聊天工具、一些游戏等。不知道大家有没有在安装完某一软件/游戏后,打开时提示缺失.dll文件的情况,对,就像下图这样,前称可能不同,但后缀一定
    clcl 5 6 0 条评论