C++如何实现一个线程池?(代码示例)

14次阅读

c++线程池实现包含阻塞任务队列、工作线程组、停止标志、条件变量和互斥锁;支持任意可调用对象入队,返回future获取结果,析构时安全等待并停止所有线程。

C++如何实现一个线程池?(代码示例)

用C++实现一个轻量、实用的线程池,核心是管理一组复用的工作线程,配合任务队列和同步机制。下面是一个基于 std::Threadstd::queuestd::mutexstd::condition_variable 的简洁实现,支持任意可调用对象(Lambda、函数指针、bind等),并具备安全停止功能。

线程池的基本结构设计

一个最小可用线程池需包含:

  • 一个阻塞任务队列(线程安全)
  • 一组运行中的工作线程
  • 控制生命周期的标志(如 m_stop
  • 用于唤醒等待线程的条件变量
  • 保护共享数据的互斥锁

完整可运行代码示例

以下为 C++11 及以上兼容的实现(无需第三方库):

立即学习C++免费学习笔记(深入)”;

#include  #include  #include  #include  #include  #include  #include  #include  

class ThreadPool { public: explicit ThreadPool(size_t threads) : m_stop(false) { for (size_t i = 0; i < threads; ++i) { m_workers.emplace_back([this] { while (true) { std::function task; { std::unique_lock lock(m_queue_mutex); m_condition.wait(lock, [this] { return m_stop || !m_tasks.empty(); }); if (m_stop && m_tasks.empty()) return; task = std::move(m_tasks.front()); m_tasks.pop(); } task(); } }); } }

templatezuojiankuohaophpcnclass F, class... Argsyoujiankuohaophpcn auto enqueue(F&& f, Args&&... args)      -youjiankuohaophpcn std::futurezuojiankuohaophpcntypename std::result_ofzuojiankuohaophpcnF(Args...) youjiankuohaophpcn::typeyoujiankuohaophpcn {     using return_type = typename std::result_ofzuojiankuohaophpcnF(Args...) youjiankuohaophpcn::type;      auto task = std::make_sharedzuojiankuohaophpcnstd::packaged_taskzuojiankuohaophpcnreturn_type()youjiankuohaophpcnyoujiankuohaophpcn(         std::bind(std::forwardzuojiankuohaophpcnFyoujiankuohaophpcn(f), std::forwardzuojiankuohaophpcnArgsyoujiankuohaophpcn(args)...)     );      std::futurezuojiankuohaophpcnreturn_typeyoujiankuohaophpcn res = task-youjiankuohaophpcnget_future();     {         std::unique_lockzuojiankuohaophpcnstd::mutexyoujiankuohaophpcn lock(m_queue_mutex);         if (m_stop) throw std::runtime_error("enqueue on stopped ThreadPool");         m_tasks.emplace([task]() { (*task)(); });     }     m_condition.notify_one();     return res; }  ~ThreadPool() {     {         std::unique_lockzuojiankuohaophpcnstd::mutexyoujiankuohaophpcn lock(m_queue_mutex);         m_stop = true;     }     m_condition.notify_all();     for (std::thread &t : m_workers) {         if (t.joinable()) t.join();     } }

private: std::vector<:thread> m_workers; std::queue<:function>> m_tasks; std::mutex m_queue_mutex; std::condition_variable m_condition; bool m_stop; };

如何使用线程池提交任务

支持无返回值和带返回值两种常见场景:

无返回值任务:

ThreadPool pool(4); pool.enqueue([]{ std::cout << "Hello from threadn"; });

带返回值任务(自动获取 future):

auto result = pool.enqueue([](int a, int b) { return a + b; }, 10, 20); std::cout << result.get() << "n"; // 输出 30

捕获局部变量的 lambda:

int x = 42; auto fut = pool.enqueue([x]{ return x * 2; }); std::cout << fut.get() << "n"; // 输出 84

注意事项与改进方向

该实现在教学和中小型项目中足够稳健,但生产环境可考虑:

  • 任务优先级支持(改用优先队列)
  • 空闲线程超时回收(避免常驻过多线程
  • 任务取消机制(需在 callable 中主动检查中断标记)
  • 更细粒度的异常传播(当前异常会终止 worker 线程)
  • 使用 std::jthread(C++20)简化析构时 join 逻辑

不复杂但容易忽略:确保所有任务对象在线程池销毁前完成,或显式等待 future;避免在任务中持有线程池自身的引用,防止循环依赖和析构死锁。

text=ZqhQzanResources