C++实现多线程任务异步调度器 _ 线程池与共享队列设计模式【源码】

轻墨同学_9825

轻墨同学_9825

2026-05-05

688人浏览

原创

线程池是防止系统崩溃的底线设计,需限制线程数、复用线程、用std::deque+mutex+cv实现安全任务队列,并通过stop标志、notify_all和join三步安全析构,配合std::packaged_task支持带返回值和异常传播的异步任务。

c++实现多线程任务异步调度器 _ 线程池与共享队列设计模式【源码】

为什么 std::thread 直接创建会压垮系统

频繁 new std::thread 启动任务,线程创建/销毁开销大,且 OS 线程数无节制增长,容易触发 std::system_error(错误码 resource_unavailable_try_again)。线程池不是“优化锦上添花”,而是防止崩溃的底线设计。

关键约束:
- 线程数通常设为 std::thread::hardware_concurrency() 或略高(如 +2),避免上下文切换反拖慢性能
- 所有线程复用,从共享队列取任务,执行完立即回池等待
- 队列必须支持多生产者单消费者(MPSC)或更通用的多生产者多消费者(MPMC),但后者需更重同步

  • 别用 std::queue 直接套 std::mutex:锁粒度太粗,入队/出队互斥,吞吐瓶颈明显
  • 避免在任务函数内抛异常未捕获——线程会 silently 终止,池中线程数悄悄减少
  • 构造线程池时就启动全部工作线程,不要懒加载;否则首次调度延迟不可控

用 std::deque + std::mutex 实现轻量安全队列

不用第三方库(如 moodycamel)时,std::deque 比 std::queue 更合适:它支持 push_back() 和 pop_front(),且迭代器不因插入失效(对锁内操作友好);配合 std::mutex 和 std::condition_variable 可实现阻塞式取任务。

核心逻辑片段:

class TaskQueue {
    std::deque<:function>> tasks_;
    mutable std::mutex mtx_;
    std::condition_variable cv_;
    std::atomic_bool stop_{false};
<p>public:
void push(std::function<void> task) {
std::lock<em>guard<:mutex> lk(mtx</:mutex></em>);
tasks_.push<em>back(std::move(task));
cv</em>.notify_one(); // 通知一个等待线程,非 broadcast
}</void></p>
<pre class="brush:php;toolbar:false;">std::function<void> pop() {
    std::unique_lock<:mutex> lk(mtx_);
    cv_.wait(lk, [this]{ return stop_ || !tasks_.empty(); });
    if (stop_ && tasks_.empty()) return {};
    auto task = std::move(tasks_.front());
    tasks_.pop_front();
    return task;
}</:mutex></void>

};

  • cv_.notify_one() 足够:每个工作线程只消费一个任务,唤醒一个即可,避免惊群
  • pop() 中的 wait 条件必须同时检查 stop_ 和 !tasks_.empty(),否则停止时可能死等
  • 返回 std::function<void></void> 时用 std::move,避免拷贝闭包对象(尤其捕获大对象时)

线程池析构时如何安全等待所有任务完成

直接在析构函数里 join 所有线程,但若此时还有任务正被 push,会死锁:push 持锁等待 cv.notify,而 worker 线程还在执行上一个任务未进入 wait —— 你等它,它等你。

正确顺序是三步断开:

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • 先原子置 stop_ = true,通知所有 worker 停止尝试取新任务
  • 再调用 cv_.notify_all(),让所有阻塞在 pop() 的线程退出 wait 并检查 stop_
  • 最后对每个 std::thread 调用 join();worker 线程内部需在 pop() 返回空函数后 break 循环

worker 线程主循环示例:

while (true) {
    auto task = queue_.pop();
    if (!task) break; // stop_ 为 true 且队列空,退出
    task();
}

注意:不能在 pop() 返回前就 join 线程,否则该线程永远卡在 wait 中。

std::packaged_task + std::future 如何绑定异步结果

用户提交任务时想拿到返回值,但线程池只接受 void() 类型。解法是用 std::packaged_task<t></t> 包一层,把任意可调用体转为能产生 std::future<t></t> 的对象。

提交接口扩展示例:

template <typename f typename... args>
auto submit(F&& f, Args&&... args) 
    -> std::future<:invoke_result_t args...>> {
    using R = std::invoke_result_t<f args...>;
    auto task = std::make_shared<:packaged_task>>(
        [f = std::forward<f>(f), ...args = std::forward<args>(args)]() mutable {
            return std::invoke(f, std::move(args)...);
        }
    );
    auto res = task->get_future();
    queue_.push([task]() { (*task)(); });
    return res;
}</args></f></:packaged_task></f></:invoke_result_t></typename>
  • 必须用 std::shared_ptr 包裹 std::packaged_task:因为任务要 move 进队列,又要在 worker 中执行,需共享所有权
  • lambda 内捕获用 std::move(args)...,避免右值参数被多次调用
  • 别直接返回 task->get_future() 后再 move task —— future 与 task 生命周期绑定,task 被 move 后 future 无效

真正难处理的是异常传播:std::packaged_task 内部抛异常会自动存入 future,调用 get() 时重抛,这点比裸线程可靠得多。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2208

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

979

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

407

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

307

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

386

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

580

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1389

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1197

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1305

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习