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.hqwc.cn/news/422724.html

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

相关文章

测试 yolov8 分割模型 边缘检测

发现 cfg/default.yaml 参数 mask_ratio 等于4 直接训练如下边缘分割标签,推理时mask 稀疏&#xff0c;训练时分数偏低,mask_ratio 改为1训练时打印的mask 的 P指标一直为0,将imgsz原图size 训练分数也不高 标注用的是labelme多边形 阅读源码发现可能是因为mask缩放导致 且出现…

P8823 [传智杯 #3 初赛] 期末考试成绩

前言: 大家好!我们又见面了~~~ 今天我来带大家学习P8823 [传智杯 #3 初赛] 期末考试成绩! 题目传送门 一、题意描述: 这道题给出一个人的成绩,这个人的成绩有三种可能: 可能性/结果情况结果x1 y1 ≥90分z1 直接输出4.0x2y2 <90分,>60z2(扣成绩-10)*0.1x3y3 &…

dpdk网络转发环境的搭建

文章目录 前言ip命令的使用配置dpdk-basicfwd需要的网络结构测试dpdk-basicfwddpdk-basicfwd代码分析附录basicfwd在tcp转发时的失败抓包信息DPDK的相关设置 前言 上手dpdk有两难。其一为环境搭建。被绑定之后的网卡没有IP&#xff0c;我如何给它发送数据呢&#xff1f;当然&a…

C++——结构体

1&#xff0c;结构体基本概念 结构体属于用户自定义的数据类型&#xff0c;允许用户存储不同的数据类型。像int&#xff08;整型&#xff09;&#xff0c;浮点型&#xff0c;bool型&#xff0c;字符串型等都是属于系统内置的数据类型。而今天要学习的结构体则是属于我们自定义…

Java 基于 SpringBoot+Vue 的社区团购系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Spring 事务原理一

从本篇博客开始&#xff0c;我们将梳理Spring事务相关的知识点。在开始前&#xff0c;想先给自己定一个目标&#xff1a;通过此次梳理要完全理解事务的基本概念及Spring实现事务的基本原理。为实现这个目标我想按以下几个步骤进行&#xff1a; 讲解事务中的一些基本概念使用Sp…

架构篇13:架构设计流程-详细方案设计

文章目录 架构设计第 4 步&#xff1a;详细方案设计详细方案设计实战小结 完成备选方案的设计和选择后&#xff0c;我们终于可以长出一口气&#xff0c;因为整个架构设计最难的一步已经完成了&#xff0c;但整体方案尚未完成&#xff0c;架构师还需继续努力。接下来我们需要再接…

java数据结构与算法刷题-----LeetCode645. 错误的集合(位运算解法需要重点掌握)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 法一&#xff1a;桶排序思想法二&#xff1a;位运算 法一&#x…

QGraphicsView前有QWidget遮罩,导致QGraphicsItem鼠标事件不响应

场景&#xff1a;在一个QWidget上放置了一个QGraphicsView用于显示图像&#xff0c;QGraphicsView设置了场景&#xff0c;并添加了一个自定义QGraphicsItem。由于需求原因&#xff0c;又绘制了一个标尺QWidget放在QGraphicsView前部。 结果导致标尺QWidget显示时&#xff0c;重…

初识进程(Linux)

进程 前言1. 介绍冯诺依曼体系结构①. CPU——寄存器、运算器、控制器和时钟②. 存储器——内存③. 输入输出设备④. 程序运行过程⑤. 小结 2. 操作系统①. 基本介绍②. 先描述再组织&#xff08;重要&#xff1a;贯穿Linux内核&#xff09; 进程1. 概念2. 了解进程①进程PCB②…

从 Vscode 中远程连接 WSL 服务器:可以本地操作虚拟机

从 Vscode 中远程连接 WSL 服务器&#xff1a;可以本地操作虚拟机 1.下载 Vscode Visual Studio Code - Code Editing. Redefined 2.搜索框中输入>wsl&#xff0c;点击 WSL&#xff1a;Connect to WSL using Distro... 3.点击下载好的Ubuntu&#xff0c;当左下角出现图片同…

工业相机与镜头参数及选型

文章目录 1、相机成像系统模型1.1 视场1.2 成像简化模型 2、工业相机参数2.1 分辨率2.2 靶面尺寸2.3 像元尺寸2.4 帧率/行频2.5 像素深度2.6 动态范围2.7 信噪比2.8 曝光时间2.9 相机接口 3、工业镜头参数3.1 焦距3.2 光圈3.3 景深3.4 镜头分辨率3.5 工作距离&#xff08;Worki…