现代 C++ 异步编程:从零实现一个高性能 ThreadPool (C++20 深度实践)

发布时间:2026/8/13 22:11:49

现代 C++ 异步编程:从零实现一个高性能 ThreadPool (C++20 深度实践)
在高性能 C 开发中线程池是绕不开的核心基础设施。随着 C20 标准的普及我们能够以更简洁、更安全的方式实现一个生产级的线程池。本文将带你深度剖析一个基于std::jthread的线程池实现并探讨其背后的架构思考与内存管理机制。1. 核心代码实现 (C20 版)这个线程池利用了 C20 的 RAII 线程管理特性彻底告别了手动join的时代。#pragmaonce#includecondition_variable#includefunctional#includefuture#includememory#includemutex#includequeue#includestdexcept#includethread#includetype_traits#includeutility#includevectorclassThreadPool{public:explicitThreadPool(std::size_t threads){if(threads0){throwstd::invalid_argument(ThreadPool requires at least one worker);}workers.reserve(threads);for(std::size_t i0;ithreads;i){// std::jthread 会自动管理线程生命周期。//// jthread 析构时会// 1. request_stop()// 2. join()//// stop_token 是 worker 获取停止请求的方式。workers.emplace_back([this](std::stop_token st){// 不要写//// while (!st.stop_requested())//// 因为我们的策略是//// 收到 stop// ↓// 不再等待新任务// ↓// 把已经在队列中的任务执行完// ↓// worker 退出//// 所以这里使用无限循环由下面的逻辑决定什么时候退出。for(;;){std::functionvoid()task;{std::unique_lockstd::mutexlock(queue_mutex);// 等待两个条件之一//// 1. tasks 非空// 2. stop_token 收到 stop 请求//// condition_variable_any 支持 stop_token// 因此 request_stop() 可以唤醒这里的 worker。//// wait() 返回//// true - predicate 满足即 tasks 非空// false - stop_token 收到了 stop 请求boolokcondition.wait(lock,st,[this]{return!tasks.empty();});// stop 请求并且任务队列已经为空//// stop true// tasks.empty() true//// 说明没有任何任务需要继续处理可以退出。if(!oktasks.empty()){return;}// 到这里有两种可能//// 1. 正常收到任务// 2. 收到 stop但队列里还有任务//// 两种情况都需要取出任务执行。taskstd::move(tasks.front());tasks.pop();}// 非常重要//// 不要持有 queue_mutex 执行任务。//// 如果任务执行时间很长而 mutex 一直被占用// 其他 worker 就无法从任务队列取任务。//// 所以//// 加锁// ↓// 取任务// ↓// 解锁// ↓// 执行任务task();}});}}~ThreadPool()default;templateclassF,class...Argsautoenqueue(Ff,Args...args)-std::futurestd::invoke_result_tF,Args...{// 获取任务函数的返回类型。//// 例如//// int foo(int);//// enqueue(foo, 10)//// return_type intusingreturn_typestd::invoke_result_tF,Args...;// packaged_task 用于//// worker 执行任务// ↓// 保存返回值// ↓// future 获取返回值//// packaged_task 本身是 move-only。//// 所以这里使用 shared_ptr 管理它的生命周期。autotaskstd::make_sharedstd::packaged_taskreturn_type()(std::bind(std::forwardF(f),std::forwardArgs(args)...));// future 是调用者获取任务执行结果的方式。std::futurereturn_typeresulttask-get_future();{std::unique_lockstd::mutexlock(queue_mutex);// tasks 的统一类型是//// std::functionvoid()//// 不管用户提交的是//// int foo()// void bar()// std::string baz()//// 最终都包装成//// void()//// worker 不需要知道任务的真实类型。tasks.emplace([task]{(*task)();});}// mutex 已经释放之后再通知 worker。//// notify_one() 唤醒一个正在等待任务的 worker。condition.notify_one();returnresult;}private:/* * 成员变量的声明顺序非常重要。 * * C 对成员变量的析构顺序是 * * 声明顺序的逆序 * * 所以这里实际上会按照 * * workers * ↓ * tasks * ↓ * condition * ↓ * queue_mutex * * 的顺序析构。 * * workers 必须最后声明。 * * 原因 * * worker 线程里面会访问 * * queue_mutex * condition * tasks * * 因此必须保证 worker 全部结束之后 * 这些对象才开始析构。 */// 保护 tasks。std::mutex queue_mutex;// condition_variable_any 支持 stop_token。std::condition_variable_any condition;// 等待执行的任务。std::queuestd::functionvoid()tasks;// 必须最后声明。//// 析构时 workers 最先被析构//// ~jthread()// ↓// request_stop()// ↓// worker 被唤醒// ↓// worker 退出// ↓// join()//// 等所有 worker 结束以后// tasks / condition / queue_mutex 才会析构。std::vectorstd::jthreadworkers;};2. 深度剖析为什么不直接存packaged_task这是初学者常有的疑问既然std::packaged_task已经封装了任务为什么队列里存的是std::functionvoid()类型擦除 (Type Erasure)std::packaged_taskR(Args...)是一个强类型模板它的类型包含了返回值R。如果任务 A 返回int任务 B 返回string它们的类型是不同的。std::queue只能存储相同类型的对象。解决方案我们利用std::functionvoid()作为“通用信封”。在enqueue内部我们写了一个 Lambda 表达式[task](){ (*task)(); }。无论原始任务返回什么这个 Lambda 永远是void()类型。这在设计模式中被称为类型擦除它抹平了不同任务之间的差异。3. 内存管理智能指针的“接力”在异步环境下最怕的是“任务还没跑对象先没了”。本实现通过std::shared_ptr和 Lambda 捕获完美解决了生存周期问题。诞生在enqueue里通过make_shared创建任务。此时计数为 1。接力Lambda 表达式通过按值捕获[task]。这意味着shared_ptr被拷贝了一份存进了 Lambda 闭包中。此时计数为 2。入队Lambda 被存入std::function并进入队列。即使enqueue函数返回闭包依然拉着shared_ptr。销毁工作线程取出并执行完任务后std::function被销毁引用计数降为 0任务对象内存自动释放。这种“引用计数闭包捕获”的机制保证了任务只要在队列中内存就绝对安全。4. C20 的技术红利std::jthread 与 RAII传统的std::thread在析构时如果不join或detach会导致进程异常退出。std::jthread引入了 RAII资源获取即初始化机制它在析构时会自动发出停止请求并等待线程结束使得线程池的析构函数极其简洁。协作式中断 (stop_token)通过std::stop_token我们不再需要手动维护一个bool stop标志。condition.wait(lock, st, pred)更是神来之笔当jthread准备停止时它会自动唤醒所有阻塞在条件变量上的线程。这比以前手动notify_all()要健壮得多。5. 如何使用intmain(){ThreadPoolpool(4);// 提交带返回值的异步任务autofuturepool.enqueue([](intx){returnx*x;},10);// 获取结果 (会阻塞直到任务完成)std::coutResult: future.get()std::endl;return0;}6. 总结实现一个线程池不难但实现一个既类型安全又内存无忧的线程池需要对 C 的底层机制有深刻理解。std::functionvoid()解决了异质任务的存储问题。std::shared_ptr解决了异步任务的生命周期问题。std::jthread解决了线程资源的回收问题。这个短小精悍的实现正是 C 现代化的魅力所在。版权声明本文采用 CC BY-SA 4.0 协议转载请注明出处。

相关新闻

Linux打印队列管理:accept命令详解与应用实践

Linux打印队列管理:accept命令详解与应用实践

2026/8/13 22:11:49

1. Linux打印队列管理基础与accept命令定位 在Linux系统中,打印服务通常由CUPS(Common UNIX Printing System)提供支持。这个开源打印系统采用IPP(Internet Printing Protocol)协议作为基础,通过守护进程方…

WPS修订模式字体颜色显示异常问题解析与解决方案

WPS修订模式字体颜色显示异常问题解析与解决方案

2026/8/13 22:11:49

1. WPS修订模式字体颜色显示异常问题解析 最近在深度使用WPS文字处理软件的修订功能时,发现一个影响工作效率的显示异常问题:当文档处于修订模式下修改文字颜色时,系统仍然会保持修订标记的红色显示,而不会实时更新为修改后的字体…

AI数字分身:从技术革新到产业落地的全链路实践

AI数字分身:从技术革新到产业落地的全链路实践

2026/8/13 22:11:49

随着人工智能技术从通用化向场景化、人格化深度演进,新质生产力的发展正迫切需要技术创新与产业应用的深度融合。数字孪生作为AI技术落地的核心载体之一,已不再局限于工业场景,正逐步渗透到企业运营、个人IP、组织管理等全领域,成…

珠海图远建设公司网站揭秘:一家老牌建设企业如何在数字化浪潮中坚守初心与匠心

珠海图远建设公司网站揭秘:一家老牌建设企业如何在数字化浪潮中坚守初心与匠心

2026/8/13 23:11:52

在珠海这座被海风轻轻拥抱、被繁华与静谧完美交织的城市的深处,有一种声音往往不被大众所熟知,却真实地支撑着城市的每一次呼吸与脉动。那就是建设者的声音。当我们在阳光明媚的傍晚漫步于情侣路,感受椰风海韵时;当我们在高楼林立的香洲核心区仰望现代建筑的几何美感时;当…

膝盖痛风急性肿痛:从剂型与药理分析外用制剂筛选思路

膝盖痛风急性肿痛:从剂型与药理分析外用制剂筛选思路

2026/8/13 23:11:52

摘要痛风发作不只局限于脚趾跖趾关节,不少患者会出现膝盖受累,关节肿胀、发热、活动受限,严重影响行走与日常活动。在风湿科规范系统治疗之外,很多人希望借助外用制剂改善局部不适感。不少饱受膝盖痛风困扰的患者都会疑惑&#xf…

Johannes 《Linux内核模块与设备驱动开发:编写Linux驱动程序》 (14-19)设备树相关

Johannes 《Linux内核模块与设备驱动开发:编写Linux驱动程序》 (14-19)设备树相关

2026/8/13 23:11:52

视频:https://www.bilibili.com/video/BV18SE26cEjn?vd_source92b7efa4daa5bb4fdcdc9f2db97c307b&p14 lesson13后面的视频是说设备树和misc 设备,感觉设备树讲的不太好,没有基础的估计完全看不懂,而且这个系列没有说中断&am…

2671亿智驾蛋糕怎么分?Momenta与地平线的“护城河”在哪里?

2671亿智驾蛋糕怎么分?Momenta与地平线的“护城河”在哪里?

2026/8/13 23:11:52

在2026年的中国智能驾驶赛道上,一场关于“谁将定义未来”的路线之争正进入白热化。根据中信建投的测算,中国智能驾驶解决方案的市场规模将在2026年飙升至2671亿元。然而,面对这块巨大的蛋糕,资本市场却给出了截然不同的定价&#…

从零构建Coding Agent:AI编程助手的技术架构与实战指南

从零构建Coding Agent:AI编程助手的技术架构与实战指南

2026/8/13 23:11:52

1. 为什么我们需要一个“会写代码”的助手?最近两年,AI领域最让人兴奋的变化之一,就是“智能体”这个概念从实验室论文和科幻电影里走了出来,开始实实在在地帮我们干活了。你可能已经习惯了用ChatGPT来写邮件、查资料,…

跨部门协作靠领导催怎么破?华恒智信成功案例

跨部门协作靠领导催怎么破?华恒智信成功案例

2026/8/13 23:01:51

【客户行业】生产制造【问题类型】流程管理【客户背景】某生产制造集团专注于高精度机械部件的研发与生产,服务于航空、汽车、医疗设备等多个高端制造业领域。近几年随着企业的不断发展、人数增加,大家都感觉到企业出现了"大企业病"&#xff0…

比较好的亚太EMBA,问了6位校友师资差别真的挺大

比较好的亚太EMBA,问了6位校友师资差别真的挺大

2026/8/13 11:01:28

比较好的亚太EMBA核心差异先看什么?对于希望兼顾工作与系统管理能力提升的亚太区高管而言,筛选匹配度高的EMBA项目时,师资配置是决定学习体验与实际收获的核心要素之一。我们结合3-4个公开信息透明、办学历史较长的亚太区主流EMBA项目特点&am…

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

2026/8/11 8:44:43

备考海外游学的亚洲EMBA面试,核心要围绕项目国际化设计逻辑、个人跨文化管理经验匹配度两个维度准备,避免把游学模块等同于普通旅游参访的认知偏差。不少备考者花3个月对比6份资料,却容易忽略面试官对“国际视野落地能力”的考察——比如香港…

比较好的国内EMBA,问了二十位校友聊透人脉价值

比较好的国内EMBA,问了二十位校友聊透人脉价值

2026/8/13 17:17:06

比较好的国内EMBA核心差异体现在哪些方面?比较好的国内EMBA的核心长期价值,很大程度上依托于校友网络的连接质量与资源生态的活跃度,这也是不少高管在择校时优先考量的因素。我们结合3-4个市场关注度较高的项目公开信息,从课程、师…

电商毛利率别再手动算了!2026年3种自动分析工具实测对比

电商毛利率别再手动算了!2026年3种自动分析工具实测对比

2026/8/13 0:00:21

一、开篇:毛利率——电商运营最该盯但最难盯的指标 电商运营中有一个指标,几乎所有老板都会问,但几乎所有运营都回答得不够确定——毛利率。不是"店铺毛利率",而是"每条链接的毛利率""每个品类的毛利率…

15-SaaS系统灰度发布:滚动更新、金丝雀发布、不停机迭代

15-SaaS系统灰度发布:滚动更新、金丝雀发布、不停机迭代

2026/8/13 0:00:21

15-SaaS系统灰度发布:滚动更新、金丝雀发布、不停机迭代 一、为什么需要不停机发布? 传统发布方式:停服务 → 替换包 → 启服务。在内部系统里勉强能用,但在SaaS系统中是灾难。 我们的无人售货柜SaaS平台服务全国几千台设备&#…

17-线上Bug热修复流程:紧急分支、补丁合并、版本快速回退方案

17-线上Bug热修复流程:紧急分支、补丁合并、版本快速回退方案

2026/8/13 0:00:21

17-线上Bug热修复流程:紧急分支、补丁合并、版本快速回退方案 前言 大家好,我是黒漂技术佬。 线上出 Bug 这种事,就像你正吃着火锅唱着歌,突然接到电话说"柜子门打不开了"。炸不炸?慌不慌?别急&a…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/8 5:07:31

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/9 13:42:46

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/8 2:30:15

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…