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.rhkb.cn/news/243353.html

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

相关文章

C# 使用System.Threading.Timer 实现计时器

写在前面 以往一般都是用 System.Timers.Timer 来做计时器&#xff0c;而 System.Threading.Timer 也可以实现计时器功能&#xff0c;并且还可以配置首次执行间隔&#xff0c;在功能上比System.Timers.Timer更加丰富&#xff1b;根据这个特性就可以实现按指定时间间隔对委托进…

2023年上半年网络工程师真题(1/3)

1.固态硬盘的存储介质是&#xff08;B&#xff09;。 A.光盘 B.闪存 C.软盘 D.磁盘 SSD存储介质是FLASH(一块块的存储芯片)&#xff0c;HDD(机械硬盘)存储介质是磁盘(机械臂和盘道)&#xff0c;补充:U盘的存储介质也是FLASH闪存。 2.虚拟存储技术把&#xff08;A&#xf…

小封装高稳定性振荡器 Sg2520egn / sg2520vgn, sg2520ehn / sg2520vhn

描述 随着物联网和ADAS等5G应用的实施&#xff0c;数据流量不断增长&#xff0c;网络基础设施变得比以往任何时候都更加重要。IT供应商一直在快速建设数据中心&#xff0c;并且对安装在数据中心内部/内部的光模块有很大的需求。此应用需要具有“小”&#xff0c;“低抖动”和“…

Linux_清理docker磁盘占用

文章目录 前言一、docker system 命令1. docker system df&#xff08;本文重点使用&#xff09;2. docker system prune&#xff08;本文重点使用&#xff09;3. docker system info4. docker system events 二、开始清理三、单独清理Build Cache四、单独清理未被使用的网络 前…

特征融合篇 | YOLOv8 引入长颈特征融合网络 Giraffe FPN

在本报告中,我们介绍了一种名为DAMO-YOLO的快速而准确的目标检测方法,其性能优于现有的YOLO系列。DAMO-YOLO是在YOLO的基础上通过引入一些新技术而扩展的,这些技术包括神经架构搜索(NAS)、高效的重参数化广义FPN(RepGFPN)、带有AlignedOTA标签分配的轻量级头部以及蒸馏增…

一文详解 Berachain 测试网:全面介绍与教程,bitget wallet教程

什么是Berachain&#xff1f; Berachain&#xff08;web3.bitget.com/zh-CN/assets/berachain-wallet&#xff09;是一种尖端区块链技术&#xff0c;使用 Cosmos SDK 构建的 Layer-1&#xff0c;兼容以太坊虚拟机&#xff08;EVM&#xff09;。它基于一种独特的概念&#xff0c…

Unity编程#region..#endregion以及面板提示语标签[Tooltip(““)]

C#中的#region..#endregion 在Unity中&#xff0c;#region和#endregion是用于代码折叠的预处理指令。它们并不是Unity特有的&#xff0c;而是C#语言本身提供的功能。 #region用于标记一段代码的开始&#xff0c;而#endregion用于标记一段代码的结束。在编辑器中&#xff0c;可…

基于YOLOv5、v7、v8的竹签计数系统的设计与实现

文章目录 前言效果演示一、实现思路① 算法原理② 程序流程图 二、系统设计与实现三、模型评估与优化① Yolov5② Yolov7③Yolov8 四、模型对比 前言 该系统是一个综合型的应用&#xff0c;基于PyTorch框架的YOLOv5、YOLOv7和YOLOv8&#xff0c;结合了Django后端和Vue3前端&am…

C内存对齐问题

一、主要参考&#xff1a; C/C编程笔记&#xff1a;C语言对齐问题【结构体、栈内存以及位域对齐】_二进制异常退出,栈对齐-CSDN博客 其中关于内存对齐&#xff0c;讲了结构体以及位域&#xff0c;以及一些容易出错的地方&#xff0c;非常好。 结构体对齐&#xff1a; 下面提…

项目风险管理

风险分类&#xff1a; 分类性质&#xff1a;纯粹风险&#xff0c;投机风险---对应火灾&#xff0c;股票买卖 产生原因&#xff1a;自然&#xff0c;社会&#xff0c;政治&#xff0c;经济&#xff0c;技术 风险性质&#xff1a;客观性&#xff0c;偶然性&#xff0c;相对性&a…

MySQL---多表等级查询综合练习

创建emp表 CREATE TABLE emp( empno INT(4) NOT NULL COMMENT 员工编号, ename VARCHAR(10) COMMENT 员工名字, job VARCHAR(10) COMMENT 职位, mgr INT(4) COMMENT 上司, hiredate DATE COMMENT 入职时间, sal INT(7) COMMENT 基本工资, comm INT(7) COMMENT 补贴, deptno INT…

锂电池SOC估计 | PatchTST时间序列模型锂电池SOC估计

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池SOC估计 | PatchTST时间序列模型锂电池SOC估计 采用新型PatchTST时间序列模型预测锂电池SOC&#xff0c;送锂电池数据集 可替换数据集&#xff0c;实现负荷预测、流量预测、降雨量预测、空气质量预测等其他多种…

[足式机器人]Part2 Dr. CAN学习笔记- 最优控制Optimal Control Ch07-2 动态规划 Dynamic Programming

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - 最优控制Optimal Control Ch07-2 动态规划 Dynamic Programming 1. 基本概念2. 代码详解3. 简单一维案例 1. 基本概念 Richoard Bell man 最优化理论&#xff1a; An optimal policy has the …

Spring-配置文件

一、引子 了解完Spring的基本概念后&#xff0c;我们紧接着来了解Spring中的核心文件--Spring配置文件。 二、配置Bean 我们在上一节Spring的基本概念中快速使用了一下Spring&#xff0c;其中我们在配置文件中主要涉及到就是Bean标签的配置&#xff1a;主要的配置字段有id, …

【漏洞攻击之文件上传条件竞争】

漏洞攻击之文件上传条件竞争 wzsc_文件上传漏洞现象与分析思路编写攻击脚本和重放措施中国蚁剑拿flag wzsc_文件上传 漏洞现象与分析 只有一个upload前端标签元素&#xff0c;并且上传任意文件都会跳转到upload.php页面&#xff0c;判定是一个apache容器&#xff0c;开始扫描…

Windows 下ffmpeg安装及实践

Windows 下ffmpeg安装及实践 背景安装实践其他 背景 最近负责音频文件处理相关的业务&#xff0c;涉及到 ffmpeg 对一些音频文件格式的校验&#xff0c;记录一下安装过程及踩坑过程。 安装 如图1所示&#xff0c;进入官网&#xff0c;在windows下任选一个文件&#xff1a;h…

【笔记】Blender4.0建模入门-3物体的基本操作

Blender入门 ——邵发 3.1 物体的移动 演示&#xff1a; 1、选中一个物体 2、选中移动工具 3、移动 - 沿坐标轴移动 - 在坐标平面内移动 - 自由移动&#xff08;不好控制&#xff09; 选中物体&#xff1a;右上的大纲窗口&#xff0c;点击物体名称&#xff0c;物体的轮…

大模型笔记【3】 gem5 运行模型框架LLama

一 LLama.cpp LLama.cpp 支持x86&#xff0c;arm&#xff0c;gpu的编译。 1. github 下载llama.cpp https://github.com/ggerganov/llama.cpp.git 2. gem5支持arm架构比较好&#xff0c;所以我们使用编译LLama.cpp。 以下是我对Makefile的修改 开始编译&#xff1a; make UNAME…

利用 ChatGPT 高效搜索:举一反三的思考方式,高效查找解决方案

文章目录 基础思路举一反三全面了解 GO 的 Web 框架系统方案建议 - 让 ChatGPT 推断我的一些微末思考结论 本文只是我的一些尝试&#xff0c;基于 ChatGPT 实现系统化快速搜索某编程语言的特定领域相关包或者基于其他语言类推荐落地方案的尝试。 这篇文章中描述的方式不一定是…

python高级(1): 迭代器详解

文章目录 1. 迭代器与可迭代对象(Iterable)1.1 可迭代对象(Iterable)1.2 迭代器( Iterator) 2. 自定义一个可迭代器2.1 实现迭代器2.2 for 遍历迭代器的过程 3. yolov8 Dataset实现案例 Python迭代器的作用是提供一种遍历数据集合的方式。它是一个可以被迭代的对象&#xff0c;…