当前位置: 首页 > news >正文

高阶开发基础——快速入门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 实现一个无返回的线程池 实现一个简单的线程池非常简单&#xff0c;我们首先聊一聊线程池的定义&#xff1a; 线程池&#xff08;Thread Pool&#xff09; 是一种并发编程的设计模式&#xff0c;用于管理和复用多个线程…...

Jupyterlab和notebook修改文件的默认存放路径的方法

文章目录 1.缘由2.操作流程2.1找到默认的路径2.2创建配置文件2.3修改配置文件内容2.4注意事项 1.缘由 我自己使用jupyterlab的时候&#xff0c;打开是在这个浏览器上面打开的&#xff0c;但是这个打开的文件路径显示的是C盘上面路径&#xff0c;所以这个就很麻烦&#xff0c;因…...

吴恩达深度学习——有效运作神经网络

内容来自https://www.bilibili.com/video/BV1FT4y1E74V&#xff0c;仅为本人学习所用。 文章目录 训练集、验证集、测试集偏差、方差正则化正则化参数为什么正则化可以减少过拟合Dropout正则化Inverted Dropout其他的正则化方法数据增广Early stopping 归一化梯度消失与梯度爆…...

享元模式——C++实现

目录 1. 享元模式简介 2. 代码示例 1. 享元模式简介 享元模式是一种结构型模式。 享元模式用于缓存共享对象&#xff0c;降低内存消耗。共享对象相同的部分&#xff0c;避免创建大量相同的对象&#xff0c;减少内存占用。 享元模式需要将对象分成内部状态和外部状态两个部分…...

【Go语言圣经】第五节:函数

第五章&#xff1a;函数 5.1 函数声明 和其它语言类似&#xff0c;Golang 的函数声明包括函数名、形参列表、返回值列表&#xff08;可省略&#xff09;以及函数体&#xff1a; func name(parameter-list) (result-list) {/* ... Body ... */ }需要注意的是&#xff0c;函数…...

win32汇编环境,窗口程序中使用进度条控件

;运行效果 ;win32汇编环境,窗口程序中使用进度条控件 ;进度条控件主要涉及的是长度单位&#xff0c;每步步长&#xff0c;推进的时间。 ;比如你的长度是1000&#xff0c;步长是100&#xff0c;每秒走1次&#xff0c;则10秒走完全程 ;比如你的长度是1000&#xff0c;步长是10&am…...

Vscode的AI插件 —— Cline

简介 vscode的一款AI辅助吃插件&#xff0c;主要用来辅助创建和编辑文件&#xff0c;探索大型项目&#xff0c;使用浏览器并执行终端命令&#xff08;需要多个tokens&#xff09;&#xff0c;可以使用模型上下文协议&#xff08;MCP&#xff09;来创建新工具并扩展自己(比较慢…...

Flink (十三) :Table API 与 DataStream API 的转换 (一)

Table API 和 DataStream API 在定义数据处理管道时同样重要。DataStream API 提供了流处理的基本操作&#xff08;即时间、状态和数据流管理&#xff09;&#xff0c;并且是一个相对低级的命令式编程 API。而 Table API 抽象了许多内部实现&#xff0c;提供了一个结构化和声明…...

Android --- handler详解

handler 理解 handler 是一套Android 消息传递机制&#xff0c;主要用于线程间通信。 tips&#xff1a; binder/socket 用于进程间通信。 参考&#xff1a; Android 进程间通信-CSDN博客 handler 就是主线程在起了一个子线程&#xff0c;子线程运行并生成message &#xff0c;l…...

[EAI-023] FAST,机器人动作专用的Tokenizer,提高VLA模型的能力和训练效率

Paper Card 论文标题&#xff1a;FAST: Efficient Action Tokenization for Vision-Language-Action Models 论文作者&#xff1a;Karl Pertsch, Kyle Stachowicz, Brian Ichter, Danny Driess, Suraj Nair, Quan Vuong, Oier Mees, Chelsea Finn, Sergey Levine 论文链接&…...

关于贪心学习的文笔记录

贪心&#xff0c;顾名思义就是越贪越好&#xff0c;越多越有易&#xff0c;他给我的感觉是&#xff0c;通常是求最大或最小问题&#xff0c;相比于动态规划贪心让人更加琢磨不透&#xff0c;不易看出方法&#xff0c;为此在这记录我所见过的题型和思维方法&#xff0c;以便回头…...

SLAM技术栈 ——《视觉SLAM十四讲》学习笔记(一)

《视觉SLAM十四讲》学习笔记&#xff08;一&#xff09; 第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 实战--孢子记账--从单体到微服务--转向微服务】--前言

在我们的专栏《单体开发》中&#xff0c;我们实现了一个简单的记账软件的服务端&#xff0c;并且成功上线。随着用户数量的不断增长&#xff0c;问题逐渐开始显现。访问量逐渐增加&#xff0c;服务端的压力也随之加大。随着访问量的攀升&#xff0c;服务端的响应时间变得越来越…...

量子力学初步:微观领域的科学之旅

飞书&#x1f4da;链接&#xff1a;量子力学篇 长尾 - 什么是量子力学 &#xff08;未完成… 等有时间再看&#xff0c;前面的内容可以参考下&#xff0c;比如了解自旋、以及斯特恩-盖拉赫实验&#xff09; 【量子力学篇-01期】经典物理学的终结&#xff0c;量子力学的开端 量…...

趣味Python100例初学者练习01

1. 1 抓交通肇事犯 一辆卡车违反交通规则&#xff0c;撞人后逃跑。现场有三人目击该事件&#xff0c;但都没有记住车号&#xff0c;只记下了车号的一些特征。甲说&#xff1a;牌照的前两位数字是相同的&#xff1b;乙说&#xff1a;牌照的后两位数字是相同的&#xff0c;但与前…...

postgresql的用户、数据库和表

在 PostgreSQL 中&#xff0c;用户、数据库和表是关系型数据库系统的基本组成部分。理解这些概念对数据库管理和操作至关重要。下面是对这些概念的详细解释&#xff1a; 1. 用户&#xff08;User&#xff09; 在 PostgreSQL 中&#xff0c;用户&#xff08;也称为 角色&#…...

对游戏宣发的粗浅思考

1.两极分化 认真观摩了mgs系列制作人的x账号&#xff0c; 其更新频率吓死人&#xff0c;一天能发几十条之多&#xff0c;吓死人。大部分都是转发相关账号的ds2或mgs相关内容&#xff0c; 每日刻意的供给这些内容来满足几十万粉丝需求&#xff0c;维护热情。 幕后是专业的公…...

【Java基础-42.3】Java 基本数据类型与字符串之间的转换:深入理解数据类型的转换方法

在 Java 开发中&#xff0c;基本数据类型与字符串之间的转换是非常常见的操作。无论是从用户输入中读取数据&#xff0c;还是将数据输出到日志或界面&#xff0c;都需要进行数据类型与字符串之间的转换。本文将深入探讨 Java 中基本数据类型与字符串之间的转换方法&#xff0c;…...

(9) 上:学习与验证 linux 里的 epoll 对象里的 EPOLLIN、 EPOLLHUP 与 EPOLLRDHUP 的不同

&#xff08;1&#xff09;经过之前的学习。俺认为结论是这样的&#xff0c;因为三次握手到四次挥手&#xff0c;到 RST 报文&#xff0c;都是 tcp 连接上收到了报文&#xff0c;这都属于读事件。所以&#xff1a; EPOLLIN : 包含了读事件&#xff0c; FIN 报文的正常四次挥手、…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1&#xff1a;HTML/CSS 前端高频面试题2&#xff1a;浏览器/计算机网络 前端高频面试题3&#xff1a;JavaScript 1.什么是强缓存、协商缓存&#xff1f; 强缓存&#xff1a; 当浏览器请求资源时&#xff0c;首先检查本地缓存是否命中。如果命…...