C++11手撕线程池 call_once 单例模式 Singleton / condition_variable 与其使用场景

一、call_once 单例模式 Singleton 

大家可以先看这篇文章:https://zh.cppreference.com/w/cpp/thread/call_once

/*std::call_oncevoid call_once( std::once_flag& flag, Callable&& f, Args&&... args );
*/
#include <iostream>
#include <mutex>
#include <thread>std::once_flag flag1, flag2;void simple_do_once() {std::call_once(flag1, []() {std::cout << "简单样例:调用一次\n";});
}void test1() {std::thread st1(simple_do_once);std::thread st2(simple_do_once);std::thread st3(simple_do_once);std::thread st4(simple_do_once);st1.join();st2.join();st3.join();st4.join();
}void may_throw_function(bool do_throw) {if (do_throw) {std::cout << "抛出:call_once 会重试\n"; // 这会出现不止一次throw std::exception();}std::cout << "没有抛出,call_once 不会再重试\n"; // 保证一次
}void do_once(bool do_throw) {try {std::call_once(flag2, may_throw_function, do_throw);}catch (...) {}
}void test2() {std::thread t1(do_once, true);std::thread t2(do_once, true);std::thread t3(do_once, false);std::thread t4(do_once, true);t1.join();t2.join();t3.join();t4.join();
}
int main() {test1();test2();return 0;
}

call_once 应用在单例模式,以及关于单例模式我的往期文章推荐:C++ 设计模式----“对象性能“模式_爱编程的大丙 设计模式-CSDN博客icon-default.png?t=N7T8https://heheda.blog.csdn.net/article/details/131466271

懒汉是一开始不会实例化,什么时候用就什么时候new,才会实例化
饿汉在一开始类加载的时候就已经实例化,并且创建单例对象,以后只管用即可
--来自百度文库
#include <iostream>
#include <thread>
#include <mutex>
#include <string>// 日志类:在整个项目中,有提示信息或者有报错信息,都通过这个类来打印
// 这些信息到日志文件,或者打印到屏幕上。显然,全局只需要一个日志类的
// 对象就可以完成所有的打印操作了。不需要第二个类来操作,这个时候就可以
// 使用单例模式来设计它std::once_flag onceFlag;
class Log {
public:Log(const Log& log) = delete;Log& operator=(const Log& log) = delete;// static Log& getInstance() { //     static Log log; // 饿汉模式//     return log;// }static Log& getInstance() { // 懒汉模式std::call_once(onceFlag, []() {std::cout << "简单样例:调用一次\n";log = new Log;});return *log;}void PrintLog(std::string msg) {std::cout << __TIME__ << msg << std::endl;}
private:Log() {};static Log* log; 
};
Log* Log::log = nullptr;void func() {Log::getInstance().PrintLog("这是一个提示");
}void print_error() {Log::getInstance().PrintLog("发现一个错误");
}void test() {std::thread t1(print_error);std::thread t2(print_error);std::thread t3(func);t1.join();t2.join();t3.join();
}int main() {test();return 0;
}

二、condition_variable 与其使用场景

#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <queue>std::queue<int> queue;
std::condition_variable cond;
std::mutex mtx;void Producer() {for (int i = 0; i < 10; i++) {{std::unique_lock<std::mutex> locker(mtx);queue.push(i);cond.notify_one();std::cout << "Producer : " << i << std::endl;}std::this_thread::sleep_for(std::chrono::microseconds(100));}
}void Consumer() {while (1) {std::unique_lock<std::mutex> locker(mtx);cond.wait(locker, []() {return !queue.empty();});int value = queue.front();queue.pop();std::cout << "Consumer :" << value << std::endl;}
}int main() {std::thread t1(Producer);std::thread t2(Consumer);t1.join();t2.join();return 0;
}

三、C++11 手撕线程池 + 单例模式(call_once)

  • ThreadPool.h
#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <condition_variable>
#include <queue>
#include <vector>
#include <functional>
std::once_flag onceFlag;
class ThreadPool {
private:ThreadPool();
public:ThreadPool(const ThreadPool& obj) = delete;ThreadPool& operator=(const ThreadPool& obj) = delete;static ThreadPool& getInstance();~ThreadPool();template<class F, class... Args>void enqueue(F&& f, Args&&... args) {std::function<void()> task =std::bind(std::forward<F>(f), std::forward<Args>(args)...);{std::unique_lock<std::mutex> locker(mtx);tasks.emplace(std::move(task));}cond.notify_one();}inline void setNum(int num) {threadNum = num;}inline void printNum() {std::cout << "线程数量为:" << threadNum << std::endl;}
private:static ThreadPool* pool;std::vector<std::thread> threads;// 线程数组std::queue<std::function<void()>> tasks;//任务队列std::mutex mtx;// 互斥锁std::condition_variable cond;//条件变量bool stop;int threadNum;// 线程数量
};
  • ThreadPool.cpp
#include "ThreadPool.h"
#include <iostream>
ThreadPool* ThreadPool::pool = nullptr;
ThreadPool::ThreadPool() {stop = false;threadNum = 4;for (int i = 0; i < threadNum; ++i) {threads.emplace_back([this]() {while (1) {std::unique_lock<std::mutex> locker(mtx);cond.wait(locker, [this]() {return !tasks.empty() || stop;});if (stop && tasks.empty()) {return;}std::function<void()> task(std::move(tasks.front()));tasks.pop();task();// 执行这个任务}});}
}ThreadPool::~ThreadPool() {{std::unique_lock<std::mutex> locker(mtx);stop = true;}cond.notify_all();for (auto& t : threads) {t.join();}
}ThreadPool& ThreadPool::getInstance() { // 懒汉模式std::call_once(onceFlag, []() {std::cout << "懒汉模式:调用一次" << std::endl;pool = new ThreadPool();});return *pool;
}
  •  main.cpp
#include <iostream>
#include "ThreadPool.h"
#include <thread>
void addTask() {ThreadPool& pool = ThreadPool::getInstance();pool.setNum(8);for (int i = 0; i < 10; ++i) {pool.enqueue([i]() {std::cout << "task : " << i << " is runing!" << std::endl;std::this_thread::sleep_for(std::chrono::microseconds(10));std::cout << "task : " << i << " is done!" << std::endl;});}
}void test() {std::thread t1(addTask);std::thread t2(addTask);std::thread t3(addTask);t1.join();t2.join();t3.join();
}int main() {test();return 0;
}

运行结果:

懒汉模式:调用一次
task : 0 is runing!
task : 0 is done!
task : 0 is runing!
task : 0 is done!
task : 1 is runing!
task : 1 is done!
task : 0 is runing!
task : 0 is done!
task : 1 is runing!
task : 1 is done!
task : 1 is runing!
task : 1 is done!
task : 2 is runing!
task : 2 is done!
task : 3 is runing!
task : 3 is done!
task : 2 is runing!
task : 2 is done!
task : 4 is runing!
task : 4 is done!
task : 3 is runing!
task : 3 is done!
task : 2 is runing!
task : 2 is done!
task : 3 is runing!
task : 3 is done!
task : 4 is runing!
task : 4 is done!
task : 5 is runing!
task : 5 is done!
task : 4 is runing!
task : 4 is done!
task : 5 is runing!
task : 5 is done!
task : 6 is runing!
task : 6 is done!
task : 7 is runing!
task : 7 is done!
task : 8 is runing!
task : 8 is done!
task : 9 is runing!
task : 9 is done!
task : 6 is runing!
task : 6 is done!
task : 7 is runing!
task : 7 is done!
task : 5 is runing!
task : 5 is done!
task : 6 is runing!
task : 6 is done!
task : 8 is runing!
task : 8 is done!
task : 9 is runing!
task : 9 is done!
task : 7 is runing!
task : 7 is done!
task : 8 is runing!
task : 8 is done!
task : 9 is runing!D:\Work\vsproject\c++11\x64\Debug\c++11.exe (进程 32636)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

未完待续~ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/639492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DT浏览器的人工智能是如何学习知识的

DT浏览器的人工智能是如何学习知识的&#xff0c;DT浏览器的人工智能通过大量的数据和算法来实现知识学习的。这是一些学习知识的方式&#xff1a; 1. 数据驱动学习&#xff1a;通过处理和分析大量的文本数据来学习语言知识和语言模式。这些数据可以来自各种来源&#xff0c;如…

解决 pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1,因为在此系统上禁止运行脚本。

执行下面命令进行安装pnpm安装后 npm install -g pnpm 然后执行pnpm 报错 解决办法&#xff1a; 以管理员身份运行 Windows PowerShell &#xff0c; 在命令行输入以下命令后按回车&#xff0c; set-ExecutionPolicy RemoteSigned 再输入Y 回车即可。 再回到控制台输入p…

k8s---包管理器helm

内容预知 目录 内容预知 helm相关知识 Helm的简介与了解 helm的三个重要概念 helm的安装和使用 将软件包拖入master01上 使用 helm 安装 Chart 对chart的基本使用 查看chart信息 安装chart 对chart的基本管理 helm自定义模板 在镜像仓库中拉取chart&#xff0c;查…

大路灯和台灯哪个对眼睛好?学生备考大灯推荐

最近家长圈里开始流行这么一句话&#xff1a;鸡娃的尽头&#xff0c;是鸡眼。曾经绘画课、科学课、乐高课、思维课一样没落下&#xff0c;讲绘本、学英语也是每天的日常&#xff0c;周一到周日孩子的行程排得满满当当。可没想到有一天带着孩子去医院体检视力的时候&#xff0c;…

python 正则表达式学习(1)

正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的检查一个字符串是否与某种模式匹配。 1. 特殊符号 1.1 符号含义 模式描述^匹配字符串的开头$匹配字符串的末尾.匹配任意字符&#xff0c;除了换行符&#xff0c;当re.DOTALL标记被指定时&#xff0c;则可以匹配包…

LangChain实战:老喻干货店社交网络Agent一

LangChain实战&#xff1a;老喻干货店社交网络Agent一 如果您也在准备AIGC前端全栈&#xff0c;LangChain是最成熟的AI应用开发框架。欢迎点赞收藏&#xff0c;一起学习AI。 LangChain 一 hello LLM LangChain 二 模型 LangChain 三 Data Connections LangChain 四 Prompts Lan…

大模型学习与实践笔记(十一)

一、使用OpenCompass 对模型进行测评 1.环境安装&#xff1a; git clone https://github.com/open-compass/opencompass cd opencompass pip install -e . 当github超时无法访问时&#xff0c;可以在原命令基础上加上地址&#xff1a; https://mirror.ghproxy.com git clon…

司铭宇老师:房地产中介销售培训课程:如何打消购房者买房疑虑

房地产中介销售培训课程&#xff1a;如何打消购房者买房疑虑 购房是一项重大的人生决定&#xff0c;它不仅涉及到巨大的经济投入&#xff0c;还关系到购房者未来的生活品质。因此&#xff0c;购房者在做出购买决定前往往会有许多疑虑和担忧。作为房地产销售人员&#xff0c;能够…

VS2022联合Qt5开发学习9(QT5.12.3鼠标按下、释放、移动事件以及Qt上取标注点)

在研究医学图像可视化的时候&#xff0c;鼠标响应这里一直都有问题。研究了几天VTK的取点&#xff0c;还是会和Qt冲突。所以现在试试Qt的方式取点&#xff0c;看看能不能实现我的功能。 查了很多资料&#xff0c;这篇博文里的实例有部分参考了祥知道-CSDN博客这位博主的博客[Q…

超级菜鸟怎么学习数据分析?

如果你有python入门基础&#xff0c;在考虑数据分析岗&#xff0c;这篇文章将带你了解&#xff1a;数据分析人才的薪资水平&#xff0c;数据人应该掌握的技术栈。 首先来看看&#xff0c;我在搜索数据分析招聘时&#xff0c;各大厂开出的薪资&#xff1a; 那各大厂在数据领域…

DC电源模块的特点及应用案例分享

BOSHIDA DC电源模块的特点及应用案例分享 DC电源模块是一种可以将交流电转换为直流电的设备&#xff0c;具有以下特点&#xff1a; 1.高效稳定&#xff1a;DC电源模块采用高效稳定的电源转换技术&#xff0c;可以将输入的交流电转换为输出的稳定直流电&#xff0c;并且具有高…

什么是游戏盾?哪家效果好。

游戏盾是什么呢&#xff0c;很多做游戏开发的客户估计都是听说过的&#xff0c;但是也不是所有的游戏开发者会运用到。因为&#xff0c;游戏盾是针对游戏行业APP业务所推出的高度可定制的网络安全管理解决方案&#xff0c;除了能针对大型DDoS攻击(T级别)进行有效防御外&#xf…

Leetcode的AC指南 —— 栈与队列:232.用栈实现队列

摘要&#xff1a; **Leetcode的AC指南 —— 栈与队列&#xff1a;232.用栈实现队列 **。题目介绍&#xff1a;请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a;…

列表列添加千分位保留两位小数

// 千分位无小数部分 function setThousandsMarkNoDecimal(num) {// console.log(num????, num, typeof num)if (!num) return num;let fu false;if (num.toString().includes(-)) {fu true;num Number(num.toString().substr(1));}// num Math.trunc(num); // 保留整数…

【Spring 篇】MyBatis注解开发:编写你的数据乐章

欢迎来到MyBatis的音乐殿堂&#xff01;在这个充满节奏和韵律的舞台上&#xff0c;注解是我们编写数据乐章的得力助手。无需繁琐的XML配置&#xff0c;通过简单而强大的注解&#xff0c;你将能够轻松地与数据库交互。在这篇博客中&#xff0c;我们将深入探讨MyBatis注解开发的精…

潜水泵如何实现远程状态监测与预测性维护?

在各行各业&#xff0c;潜水泵的健康数据采集一直是一项具有挑战性的任务。然而&#xff0c;一项被称为电气特征分析&#xff08;ESA&#xff09;的技术通过在电机控制柜而非泵本身上安装传感器&#xff0c;成功解决了这一问题。 图.泵&#xff08;iStock&#xff09; 一、电气…

Ubuntu重设root的密码

重设root的密码 未重设密码之前&#xff0c;Ubuntu 中默认的 root 密码是随机的&#xff0c;即每次开机都会有一个新的root 密码&#xff0c;所以此时的 root 用户密码并不确定&#xff1b; 重设root 密码&#xff0c;使用安装时创建的用户登录后sudo su切换至root用户&#…

云服务器搭建coturn出现Not reachable?

文章目录 问题复现解决方案1. 云服务器端口开放问题2. 检查配置文件3. 浏览器 问题解决 问题复现 使用云服务器搭建coturn服务时&#xff0c;出现not reachable报错 ICE Server配置是正确的 但测试relay时却报错&#xff1a;not reachable? 并且服务器也没输出相应日志。 …

(2021|ICLR,扩散先验,VE-SDE,逼真和忠实的权衡)SDEdit:使用随机微分方程引导图像合成和编辑

SDEdit: Guided Image Synthesis and Editing with Stochastic Differential Equations 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 背景&#xff1a;使用随机微分方程…

vue3-生命周期

生命周期 生命周期 vue 组件实例都有自己的一个生命周期 从创建->初始化数据->编译模版->挂载实例到 DOM->数据变更后更新 DOM ->卸载组件 生命周期简单说就是 vue 实例从创建到销毁的过程 生命周期钩子 在各个周期运行时&#xff0c;会执行钩子函数&…