C++11并发与多线程笔记(7)单例设计模式共享数据分析、解决,call_once
2021/11/6 11:09:58
本文主要是介绍C++11并发与多线程笔记(7)单例设计模式共享数据分析、解决,call_once,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 1、设计模式大概谈
- 2、单例设计模式
- 3、单例设计模式共享数据问题分析、解决
- 4、std::call_once()
1、设计模式大概谈
设计模式
- 代码的一些写法(这些写法跟常规写法不怎么一样),这样代码写出来的程序灵活,维护起来可能方便,但是别人接管,阅读代码非常痛苦。
- 用“设计模式”理念写出来的代码是很晦涩的;
- 当应付特别大的项目的时候,把项目的开发经验、模块划分经验,总结整理成设计模式(先有开发需求,后有理论总结和整理)。
- 设计模式肯定有它独特的优点,要活学活用,不要深陷其中,生搬硬套。
2、单例设计模式
- 单例设计模式,使用的频率比较高;
- 整个项目中,有某个或者某些特殊的类,属于该类的对象,只能创建一个,多了创建不了。
示例代码:
#include <iostream> using namespace std; class MyCAS { private: MyCAS() {} //私有化构造函数 private: static MyCAS* m_instance; //静态成员变量 public: static MyCAS* GetInstance() { if (m_instance == NULL) { m_instance = new MyCAS(); static CGarhuishou cl; } return m_instance; } class CGarhuishou //类中套类,用来释放对象 { public: ~CGarhuishou() { if (MyCAS::m_instance) { delete MyCAS::m_instance; MyCAS::m_instance = NULL; } } }; void func() { cout << "测试" << endl; } }; //类静态变量初始化 MyCAS* MyCAS::m_instance = NULL; int main() { MyCAS* p_a = MyCAS::GetInstance(); //创建一个对象,返回该类(MyCAS)对象的指针 MyCAS* p_b = MyCAS::GetInstance(); p_a->func(); MyCAS::GetInstance()->func(); return 0; }
3、单例设计模式共享数据问题分析、解决
- 面临的问题:需要在我们自己创建的线程(而不是主线程)中来创建
MyCAS
这个单例类的对象,这种线程可能不止1个(至少2个)。 - 我们可能会面临
GetInstance()
这种成员函数要互斥。 - 采用双重锁定来提升效率,这样就不用每次进
GetInstance()
函数都要加一次锁,解一次锁。
示例代码:
#include <iostream> #include <thread> #include <mutex> using namespace std; std::mutex resource_mutex; class MyCAS { private: MyCAS() {} //私有化构造函数 private: static MyCAS* m_instance; //静态成员变量 public: 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; } class CGarhuishou //类中套类,用来释放对象 { public: ~CGarhuishou() { if (MyCAS::m_instance) { delete MyCAS::m_instance; MyCAS::m_instance = NULL; } } }; void func() { cout << "测试" << endl; } }; //类静态变量初始化 MyCAS* MyCAS::m_instance = NULL; void mythread() { cout << "我的线程开始执行了" << endl; MyCAS* p_a = MyCAS::GetInstance(); cout << "我的线程执行完毕了" << endl; } int main() { std::thread mytobj1(mythread); std::thread mytobj2(mythread); /*虽然这两个线程是同一个入口函数, 但大家千万要记住,这是两个线程, 所以这里会有两个流程(两条通路)同时开始执行mythread这个函数 */ mytobj1.join(); mytobj2.join(); return 0; }
4、std::call_once()
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 <mutex> using namespace std; std::mutex resource_mutex; std::once_flag g_flag; //系统定义的标记 class MyCAS { static void CreatInstance() //只被调用一次 { std::chrono::milliseconds dura(20000); //休息20s std::this_thread::sleep_for(dura); cout << "CreatInstance()被执行了" << endl; m_instance = new MyCAS(); static CGarhuishou cl; } private: MyCAS() {} //私有化构造函数 private: static MyCAS* m_instance; //静态成员变量 public: static MyCAS* GetInstance() { std::call_once(g_flag, CreatInstance); //两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕CreatInstance() cout << "call_once()执行完毕" << endl; return m_instance; } class CGarhuishou //类中套类,用来释放对象 { public: ~CGarhuishou() { if (MyCAS::m_instance) { delete MyCAS::m_instance; MyCAS::m_instance = NULL; } } }; void func() { cout << "测试" << endl; } }; //类静态变量初始化 MyCAS* MyCAS::m_instance = NULL; void mythread() { cout << "我的线程开始执行了" << endl; MyCAS* p_a = MyCAS::GetInstance(); p_a->func(); cout << "我的线程执行完毕了" << endl; return; } int main() { std::thread mytobj1(mythread); std::thread mytobj2(mythread); /*虽然这两个线程是同一个入口函数, 但大家千万要记住,这是两个线程, 所以这里会有两个流程(两条通路)同时开始执行mythread这个函数 */ mytobj1.join(); mytobj2.join(); return 0; }
- 建议还是在主函数(主线程)中先创建好单例对象,然后再创建子线程。
std::call_once
的效率实际上比双重锁定要低,还是建议使用双重锁定。
注:本人学习c++多线程视频地址:C++多线程学习地址
这篇关于C++11并发与多线程笔记(7)单例设计模式共享数据分析、解决,call_once的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-07fastcgi 是什么-icode9专业技术文章分享
- 2024-10-07fastcgi 的详细使用教程介绍-icode9专业技术文章分享
- 2024-10-07git如何更新单个文件到本地-icode9专业技术文章分享
- 2024-10-07如何使用ASM(Abstract Syntax Tree Manipulation)技术来修改第三方AAR依赖中的函数-icode9专业技术文章分享
- 2024-10-07Activity 跳转时间耗时很长怎么优化解决-icode9专业技术文章分享
- 2024-10-07Androud Toast 有哪些常用的第三方组件-icode9专业技术文章分享
- 2024-10-07在viewmodel中怎么使用 mmkv?-icode9专业技术文章分享
- 2024-10-07MMKV.defaultMMKV() 是单例模式吗?-icode9专业技术文章分享
- 2024-10-04el-table 开启定时器下,表格的选中状态会消失是什么原因-icode9专业技术文章分享
- 2024-10-03如何安装和初始化飞牛私有云 fnOS?-icode9专业技术文章分享