直接用 std::Thread 不适合高频小任务,因其创建销毁开销大且无法控并发;线程池通过复用固定线程、共享阻塞队列和原子停止标志实现高效任务调度。

为什么直接用 std::thread 不适合高频小任务
频繁创建销毁 std::thread 开销大,线程栈分配、上下文切换、系统调用都会拖慢性能;任务提交和执行耦合,无法控制并发数,容易压垮系统。线程池本质是复用一组固定线程,把任务排队交给空闲线程处理。
核心组件怎么组织(不依赖第三方库)
一个最小可用线程池需包含:任务队列(std::queue + std::mutex + std::condition_variable)、线程集合(std::vector<:thread>)、停止标志(std::atomic)。所有线程共用一个阻塞队列,通过条件变量等待新任务。
- 任务类型用
std::function,支持 Lambda、函数指针、绑定对象 - 入队用
push()加锁 + 通知,出队用wait_and_pop()阻塞等待 - 线程循环中检查
m_stop.load(),为 true 时主动退出,避免死等 - 析构时先设
m_stop = true,再notify_all()唤醒所有线程,最后join()
任务调度没那么智能:它只是 FIFO + 竞争获取
标准实现里没有优先级、超时、重试或依赖调度。所谓“调度”就是多个线程同时等待 cv.wait(),谁先被唤醒、谁先抢到互斥锁,谁就取走队首任务——完全由系统调度器决定,不可预测。如果你需要按优先级执行,得换用 std::priority_queue 并加额外同步逻辑;需要延迟执行,就得自己维护定时任务队列,不是线程池本职工作。
一个可运行的极简示例(c++17)
#include #include #include #include #include #include #include class ThreadPool { std::vector workers; std::queue> tasks; std::mutex queue_mutex; std::condition_variable cv; std::atomic m_stop{false}; public: explicit ThreadPool(size_t threads) { for (size_t i = 0; i < threads; ++i) { workers.emplace_back([this] { while (true) { std::function task; { std::unique_lock lock(queue_mutex); cv.wait(lock, [this] { return m_stop.load() || !tasks.empty(); }); if (m_stop.load() && tasks.empty()) return; task = std::move(tasks.front()); tasks.pop(); } task(); } }); } } ~ThreadPool() { { std::unique_lock lock(queue_mutex); m_stop = true; } cv.notify_all(); for (auto& t : workers) t.join(); } template void enqueue(F&& f, Args&&... args) { { std::unique_lock lock(queue_mutex); tasks.emplace([=] { std::forward(f)(std::forward(args)...); }); } cv.notify_one(); } };
注意 enqueue 中捕获方式用 [=] 而非 [&],避免引用外部局部变量导致悬垂;notify_one() 比 notify_all() 更轻量,够用;真正上线前还得考虑异常安全——比如 task() 抛异常会终止线程,需要在 worker 循环里加 try/catch。
立即学习“C++免费学习笔记(深入)”;