高阶开发基础——快速入门C++并发编程6——大作业:实现一个超级迷你的线程池
目录
实现一个无返回的线程池
完全代码实现
Reference
实现一个无返回的线程池
实现一个简单的线程池非常简单,我们首先聊一聊线程池的定义:
线程池(Thread Pool) 是一种并发编程的设计模式,用于管理和复用多个线程,以提高程序的性能和资源利用率。它的核心思想是预先创建一组线程,并将任务分配给这些线程执行,而不是为每个任务单独创建和销毁线程。线程池广泛应用于需要处理大量短期任务的场景,例如 Web 服务器、数据库连接池、任务调度系统等。换而言之,线程池说白了就是一种饿汉思维——直接预先提供若干的线程,由线程池内部控制调度,确保我们可以只关心任务的提交以及完成。
我们下面要做的是设计一个任务是不返回的线程池。所以,我们约束我们的函数是:
using supportive_task_type = std::function<void()>;
下一步,就是构造我们的线程池的线程。注意的是——线程和任务是解耦合的,意味着我们需要一个中间函数解耦合任务派发。笔者决定,将任务派发分到一个私有函数完成:
CCThreadPool(const int workers_num) {for(int i = 0; i < workers_num; i++){internal_threads.emplace_back([this](){__scheduled();});}}
上面这个代码很简单,就是将每一个线程都分配一个调度函数,这个调度函数来委派分发任务,办法说简单也很简单:
void __scheduled(){while(1){// sources protectionsstd::unique_lock<std::mutex> locker(internal_mutex);// waiting for the access of the task resourcescontrolling_cv.wait(locker, [this]{return thread_pool_status || !tasks_queue.empty();});// quit if requriedif(thread_pool_status && tasks_queue.empty()){return;}// 现在我们可以取到任务执行了supportive_task_type task(std::move(tasks_queue.front()));tasks_queue.pop();locker.unlock();task();}}
当析构的时候,我们也要通知所有线程的cv不要睡眠了,由于设置了thread_pool_status是true,直接线程跳出来结束全文。
~CCThreadPool(){thread_pool_status = true;controlling_cv.notify_all();for(auto& thread : internal_threads){thread.join();}}
完全代码实现
#include <condition_variable>
#include <functional>
#include <mutex>
#include <print>
#include <queue>
#include <thread>
#include <utility>
#include <vector>
class CCThreadPool {public:CCThreadPool() = delete;CCThreadPool(const CCThreadPool &) = delete;CCThreadPool &operator=(CCThreadPool &) = delete;
CCThreadPool(const int workers_num) {for(int i = 0; i < workers_num; i++){internal_threads.emplace_back([this](){__scheduled();});}}
~CCThreadPool(){thread_pool_status = true;controlling_cv.notify_all();for(auto& thread : internal_threads){thread.join();}}
template<typename F, typename... Args>void enTask(F&& f, Args&&... args){supportive_task_type task(std::bind(std::forward<F&&>(f), std::forward<Args&&>(args)...));{std::unique_lock<std::mutex> locker(internal_mutex);tasks_queue.emplace(std::move(task));}controlling_cv.notify_one();}
private:void __scheduled(){while(1){std::unique_lock<std::mutex> locker(internal_mutex);controlling_cv.wait(locker, [this]{return thread_pool_status || !tasks_queue.empty();});// quitif(thread_pool_status && tasks_queue.empty()){return;}supportive_task_type task(std::move(tasks_queue.front()));tasks_queue.pop();locker.unlock();task();}}
using supportive_task_type = std::function<void()>;std::vector<std::thread> internal_threads;std::queue<supportive_task_type> tasks_queue;std::mutex internal_mutex;std::condition_variable controlling_cv;bool thread_pool_status = false;
};
int main()
{std::println("Task start");CCThreadPool pool(4);for (int i = 0; i < 8; ++i) {pool.enTask([i] {std::println("Task {} is started at thread with id {}", i, std::this_thread::get_id());std::this_thread::sleep_for(std::chrono::seconds(1));std::println("Task {} is done", i);});}return 0;
}
Reference
8. C++11 跨平台线程池-See的编程日记 (seestudy.cn)
相关文章:
高阶开发基础——快速入门C++并发编程6——大作业:实现一个超级迷你的线程池
目录 实现一个无返回的线程池 完全代码实现 Reference 实现一个无返回的线程池 实现一个简单的线程池非常简单,我们首先聊一聊线程池的定义: 线程池(Thread Pool) 是一种并发编程的设计模式,用于管理和复用多个线程…...
Jupyterlab和notebook修改文件的默认存放路径的方法
文章目录 1.缘由2.操作流程2.1找到默认的路径2.2创建配置文件2.3修改配置文件内容2.4注意事项 1.缘由 我自己使用jupyterlab的时候,打开是在这个浏览器上面打开的,但是这个打开的文件路径显示的是C盘上面路径,所以这个就很麻烦,因…...
吴恩达深度学习——有效运作神经网络
内容来自https://www.bilibili.com/video/BV1FT4y1E74V,仅为本人学习所用。 文章目录 训练集、验证集、测试集偏差、方差正则化正则化参数为什么正则化可以减少过拟合Dropout正则化Inverted Dropout其他的正则化方法数据增广Early stopping 归一化梯度消失与梯度爆…...
享元模式——C++实现
目录 1. 享元模式简介 2. 代码示例 1. 享元模式简介 享元模式是一种结构型模式。 享元模式用于缓存共享对象,降低内存消耗。共享对象相同的部分,避免创建大量相同的对象,减少内存占用。 享元模式需要将对象分成内部状态和外部状态两个部分…...
【Go语言圣经】第五节:函数
第五章:函数 5.1 函数声明 和其它语言类似,Golang 的函数声明包括函数名、形参列表、返回值列表(可省略)以及函数体: func name(parameter-list) (result-list) {/* ... Body ... */ }需要注意的是,函数…...
win32汇编环境,窗口程序中使用进度条控件
;运行效果 ;win32汇编环境,窗口程序中使用进度条控件 ;进度条控件主要涉及的是长度单位,每步步长,推进的时间。 ;比如你的长度是1000,步长是100,每秒走1次,则10秒走完全程 ;比如你的长度是1000,步长是10&am…...
Vscode的AI插件 —— Cline
简介 vscode的一款AI辅助吃插件,主要用来辅助创建和编辑文件,探索大型项目,使用浏览器并执行终端命令(需要多个tokens),可以使用模型上下文协议(MCP)来创建新工具并扩展自己(比较慢…...
Flink (十三) :Table API 与 DataStream API 的转换 (一)
Table API 和 DataStream API 在定义数据处理管道时同样重要。DataStream API 提供了流处理的基本操作(即时间、状态和数据流管理),并且是一个相对低级的命令式编程 API。而 Table API 抽象了许多内部实现,提供了一个结构化和声明…...
Android --- handler详解
handler 理解 handler 是一套Android 消息传递机制,主要用于线程间通信。 tips: binder/socket 用于进程间通信。 参考: Android 进程间通信-CSDN博客 handler 就是主线程在起了一个子线程,子线程运行并生成message ,l…...
[EAI-023] FAST,机器人动作专用的Tokenizer,提高VLA模型的能力和训练效率
Paper Card 论文标题:FAST: Efficient Action Tokenization for Vision-Language-Action Models 论文作者:Karl Pertsch, Kyle Stachowicz, Brian Ichter, Danny Driess, Suraj Nair, Quan Vuong, Oier Mees, Chelsea Finn, Sergey Levine 论文链接&…...
关于贪心学习的文笔记录
贪心,顾名思义就是越贪越好,越多越有易,他给我的感觉是,通常是求最大或最小问题,相比于动态规划贪心让人更加琢磨不透,不易看出方法,为此在这记录我所见过的题型和思维方法,以便回头…...
SLAM技术栈 ——《视觉SLAM十四讲》学习笔记(一)
《视觉SLAM十四讲》学习笔记(一) 第2讲 初识SLAM习题部分 第3讲 三维空间刚体运动3.1 左手系与右手系3.2 齐次坐标3.3 旋转矩阵与变换矩阵3.4 正交群与欧式群3.5 旋转向量与欧拉角3.6 实践Eigen线性代数库3.6.1 QR分解(QR decomposition) 3.7 四元数到其…...
【ChatGPT:开启人工智能新纪元】
一、ChatGPT 是什么 最近,ChatGPT 可是火得一塌糊涂,不管是在科技圈、媒体界,还是咱们普通人的日常聊天里,都能听到它的大名。好多人都在讨论,这 ChatGPT 到底是个啥 “神器”,能让大家这么着迷?今天咱就好好唠唠。 ChatGPT,全称是 Chat Generative Pre-trained Trans…...
1. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--前言
在我们的专栏《单体开发》中,我们实现了一个简单的记账软件的服务端,并且成功上线。随着用户数量的不断增长,问题逐渐开始显现。访问量逐渐增加,服务端的压力也随之加大。随着访问量的攀升,服务端的响应时间变得越来越…...
量子力学初步:微观领域的科学之旅
飞书📚链接:量子力学篇 长尾 - 什么是量子力学 (未完成… 等有时间再看,前面的内容可以参考下,比如了解自旋、以及斯特恩-盖拉赫实验) 【量子力学篇-01期】经典物理学的终结,量子力学的开端 量…...
趣味Python100例初学者练习01
1. 1 抓交通肇事犯 一辆卡车违反交通规则,撞人后逃跑。现场有三人目击该事件,但都没有记住车号,只记下了车号的一些特征。甲说:牌照的前两位数字是相同的;乙说:牌照的后两位数字是相同的,但与前…...
postgresql的用户、数据库和表
在 PostgreSQL 中,用户、数据库和表是关系型数据库系统的基本组成部分。理解这些概念对数据库管理和操作至关重要。下面是对这些概念的详细解释: 1. 用户(User) 在 PostgreSQL 中,用户(也称为 角色&#…...
对游戏宣发的粗浅思考
1.两极分化 认真观摩了mgs系列制作人的x账号, 其更新频率吓死人,一天能发几十条之多,吓死人。大部分都是转发相关账号的ds2或mgs相关内容, 每日刻意的供给这些内容来满足几十万粉丝需求,维护热情。 幕后是专业的公…...
【Java基础-42.3】Java 基本数据类型与字符串之间的转换:深入理解数据类型的转换方法
在 Java 开发中,基本数据类型与字符串之间的转换是非常常见的操作。无论是从用户输入中读取数据,还是将数据输出到日志或界面,都需要进行数据类型与字符串之间的转换。本文将深入探讨 Java 中基本数据类型与字符串之间的转换方法,…...
(9) 上:学习与验证 linux 里的 epoll 对象里的 EPOLLIN、 EPOLLHUP 与 EPOLLRDHUP 的不同
(1)经过之前的学习。俺认为结论是这样的,因为三次握手到四次挥手,到 RST 报文,都是 tcp 连接上收到了报文,这都属于读事件。所以: EPOLLIN : 包含了读事件, FIN 报文的正常四次挥手、…...
基于本地大模型与Playwright的隐私优先求职自动化助手RedClaw实践
1. 项目概述:一个真正为你掌控的本地化求职AI助手在求职季,我们常常面临一个两难困境:一方面,海投简历耗时耗力,重复填写那些大同小异的在线申请表让人筋疲力尽;另一方面,市面上一些所谓的“自动…...
Hummingbot自动化交易框架:从原理到实战的量化交易指南
1. 项目概述:一个为专业交易者打造的自动化交易框架如果你在加密货币交易领域摸爬滚打过一段时间,一定会对“手动盯盘”的疲惫和“情绪化操作”的代价深有体会。市场24/7运转,机会转瞬即逝,而人的精力终究有限。这正是我最初接触并…...
VS2019编译OpenSceneGraph 3.6.5踩坑全记录:从CMake配置到解决第三方库缺失
VS2019编译OpenSceneGraph 3.6.5实战避坑指南 第一次在Windows平台用VS2019编译OpenSceneGraph 3.6.5时,我原以为按照官方文档就能轻松搞定。直到CMake报出一连串第三方库缺失的红色警告,才意识到这趟编译之旅远没有想象中简单。如果你也正对着Could NOT…...
Taotoken账单详情页功能体验,让每一分Token消耗都清晰可溯
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Taotoken账单详情页功能体验,让每一分Token消耗都清晰可溯 对于任何将大模型API集成到产品开发或日常工作中的团队与个…...
手把手教你:在RT-Thread上用STM32驱动0.96寸OLED显示动态二维码(附完整源码)
基于RT-Thread的STM32动态二维码显示系统开发实战 在智能门锁、工业设备配网等物联网场景中,二维码作为信息载体正发挥着越来越重要的作用。本文将完整呈现如何在RT-Thread操作系统上,通过STM32驱动0.96寸OLED实现动态二维码显示功能。不同于简单的功能演…...
MANT量化技术:大语言模型推理的硬件架构革新
1. MANT量化技术:大语言模型推理的硬件架构革新在人工智能领域,大语言模型(LLM)的推理效率一直是制约其实际应用的关键瓶颈。传统量化方法往往面临精度损失与硬件适配的双重挑战,而MANT技术的出现为这一困境提供了创新解决方案。作为一名深耕…...
Gemini3.1Pro:商业分析框架搭建神器
做咨询的人都知道,真正难的从来不是“找到信息”,而是“把信息组织成框架”。 很多商业分析问题看起来复杂,本质上都是在有限时间内,把零散材料整理成一个能支撑判断的逻辑结构。如果你经常做行业分析、竞品分析、市场调研、经营诊…...
局域网监控软件评测:从数据主权视角看企业效能工具的取舍
很多管理者在巡视办公室时,看到员工手指在键盘上飞速跳动,屏幕上代码或表格交织,心中却往往悬着一块石头:他们是在攻克项目难关,还是在处理私人兼职?这种管理上的“黑盒状态”,不仅是效率的损耗…...
有机颜料哪个更前沿
下游行业不断升级,从环保要求到个性化着色需求都在提升,很多采购和技术负责人都会问:现在有机颜料哪个方向更前沿?其实有机颜料的技术迭代始终围绕下游需求走,没有绝对的“最优前沿”,只有更适配自身需求的…...
AI产品经理 VS 传统产品经理:不是技术升级,而是物种进化!你准备好了吗?
文章指出,AI时代的产品经理并非仅仅是懂点AI技术的传统产品经理升级版,而是完全不同的“物种”。文章从产品经理的职责、核心能力、与AI的协作模式等方面对比了传统产品经理和AI产品经理的区别,强调AI产品经理需要具备处理意图模糊性、设计失…...
