手写工业级C++线程池|解决死锁、崩溃、丢任务所有痛点🔥
做C++后端、嵌入式、高性能服务的兄弟,应该都懂一个痛:
项目一旦上高并发,原生std::thread裸写多线程,就是灾难现场。
频繁创建销毁线程、任务队列线程不安全、退出死锁、任务异常直接崩程序、关闭丢任务、无法暂停恢复......
网上90%的开源线程池,要么功能残缺,要么存在隐藏bug,根本不敢直接上生产。
今天把自己项目正在商用的完整版工业级C++11线程池开源分享出来,全程手写、无第三方依赖,修复了市面上大部分线程池的通病,细节拉满,面试、项目、毕业设计直接无脑套用!
👇先跟大家说清楚,我这份线程池到底解决了哪些行业痛点
✅ 自动适配CPU核心数,智能初始化线程数量
不用自己硬写线程数代码,默认读取硬件核心数适配,兼容各类设备。如果读取失败,兜底4核/2核保底,杜绝0线程启动的低级bug,开箱即用。
✅ 完整任务状态管理:运行/暂停/停止 全覆盖
市面上很多线程池只有启动和关闭,没有暂停恢复功能。
我这里单独封装了 PoolState、WorkerState 双层状态枚举:
线程池:运行 / 暂停 / 停止中 / 已停止
工作线程:空闲 / 运行 / 停止
支持随时pause暂停任务、resume恢复任务,控流、限流场景直接拿捏,灵活性拉满。
✅100%解决退出死锁问题(核心优化)
这是绝大多数新手写线程池最大的坑!
普通线程池用condition_variable等待任务,程序退出时,队列空了线程还在休眠,导致join死锁,程序卡死退不出。
我在等待谓词里强制处理Stopping状态:
线程池进入停止状态后,无论队列是否为空,都会唤醒所有阻塞线程,清空任务、正常退出,彻底杜绝死锁bug。
✅支持带返回值异步任务,完美适配future/promise
很多简易线程池只能跑无返回值任务,业务场景极其受限。
这份代码模板封装到位,任意函数、任意参数、有参无返回/有返回全部支持。
submit提交任务后返回future,主线程可以同步获取任务执行结果,适配所有业务需求。
同时做了void返回值特化处理,避免编译报错,细节直接拉满。
✅ 全局异常捕获,任务报错不崩线程池
普通线程池一旦任务抛异常,直接导致工作线程终止,线程池直接废了。
我这里做了全局异常捕获 + 自定义异常处理器:
单个任务崩溃、抛异常,只会捕获异常、记录异常信息,不会影响其他线程和任务执行,服务稳定性直接拉满,完全可以上生产。
✅ 两种关闭模式自由选择
shutdown关闭线程池支持两种模式:
1、等待剩余任务全部执行完再退出(正常业务关闭)
2、直接丢弃未执行任务,快速强制退出(紧急销毁场景)
根据项目场景自由切换,适配性极强。
✅ 严格线程安全 + 规范内存序
任务队列互斥锁、状态原子变量、内存序精细控制(acquire/release/relaxed)
杜绝数据竞争、指令重排导致的诡异并发bug,不是玩具代码,是工业级标准写法。
✅ 标准RAII机制,零内存泄漏
禁止拷贝构造、赋值重载,析构函数自动调用shutdown关闭线程池
无需手动管理线程资源,对象生命周期结束自动清理,杜绝内存泄漏、线程残留问题。
✅ 实时线程状态快照
可以随时获取所有工作线程状态:空闲/运行/停止
排查线程阻塞、任务堆积问题超级方便,调试效率翻倍。
🔥 为什么说这份代码吊打网上90%的线程池?
网上大部分教程线程池:
只有基础任务投递、没有状态管理、没有异常处理、关闭必死锁、不支持暂停、不支持返回值、内存序乱写、任务丢失......
我这份是项目迭代打磨过的商用版本,所有边界问题全部处理完毕:
边界空判断、状态流转校验、异常兜底、死锁规避、任务不丢失、线程不残留
💡简单说下核心使用逻辑(新手也能看懂)
1、创建线程池(不传参自动适配CPU核心数)
2、submit投递任意异步任务,自动分配空闲线程执行
3、通过future获取任务返回结果
4、随时pause暂停、resume恢复任务调度
5、程序结束自动析构关闭,无残留无泄漏
c++
#pragma once
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <queue>
#include <stdexcept>
#include <thread>
#include <type_traits>
#include <utility>
#include <vector>
namespace tp {
enum class WorkerState : std::uint8_t {
Idle,
Running,
Stopped
};
enum class PoolState : std::uint8_t {
Running,
Paused,
Stopping,
Stopped
};
namespace detail {
inline std::size_t & thread_local_worker_index() noexcept {
thread_local std::size_t idx = 0;
return idx;
}
template <typename R, typename Bound, std::enable_if_t<!std::is_void_v<R>,int> = 0>
void invoke_and_set_value(const std::shared_ptr<std::promise<R>> & promise, Bound & bound) {
promise->set_value(bound());
}
template <typename Bound>
void invoke_and_set_value(const std::shared_ptr<std::promise<void>> & promise, Bound & bound){
bound();
promise->set_value();
}
}
class ThreadPool {
public:
using ExceptionHandler = std::function<void(std::size_t worker_index, std::exception_ptr ep)>;
explicit ThreadPool(std::size_t thread_count = 0) {
const std::size_t tc = std::thread::hardware_concurrency();
std::size_t n = thread_count == 0 ? (tc == 0 ? 4u : static_cast<std::size_t>(tc)) : thread_count;
if (n == 0)
n = 2;
workers_.reserve(n);
worker_states_.reset(new std::atomic<WorkerState>[n]);
for (std::size_t i = 0; i < n; i++) {
worker_states_[i].store(WorkerState::Idle, std::memory_order_relaxed);
workers_.emplace_back([this,i]() {
worker_loop(i);
});
}
}
ThreadPool(const ThreadPool&) = delete;
ThreadPool& operator=(const ThreadPool&) = delete;
~ThreadPool() {
shutdown(true);
}
template<typename F, typename ...Args>
auto submit(F &&f, Args&&...args)
->std::future<std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>>{
using ReturnType = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>... >;
if (!accepting_tasks()) {
throw std::runtime_error("ThreadPool: pool is not accepting new tasks");
}
auto promise = std::make_shared<std::promise<ReturnType>>();
std::future<ReturnType> result = promise->get_future();
auto bound = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
{
std::unique_lock<std::mutex> lock(queque_mutex_);
if (!accepting_tasks()) {
throw std::runtime_error("ThreadPool: pool stopped before task was queued");
}
tasks_.emplace([this, promise, bound = std::move(bound)]() mutable {
const std::size_t wid = detail::thread_local_worker_index();
try {
detail::invoke_and_set_value(promise, bound);
}
catch (...) {
std::exception_ptr ep = std::current_exception();
invoke_exception_handler(wid, ep);
promise->set_exception(ep);
}
});
}
condition_.notify_all();
return result;
}
void pause() {
pool_state_.store(PoolState::Paused, std::memory_order_release);
condition_.notify_all();
}
void resume() {
PoolState expected = PoolState::Paused;
if (pool_state_.compare_exchange_strong(expected, PoolState::Running, std::memory_order_acq_rel)) {
condition_.notify_all();
}
}
void shutdown(bool wait_pending = true) {
if (pool_state_.load(std::memory_order_acquire) == PoolState::Stopped)
return;
{
std::unique_lock<std::mutex> lock(queque_mutex_);
pool_state_.store(PoolState::Stopping, std::memory_order_release);
discard_remaining_tasks_on_stop_ = !wait_pending;
if (!wait_pending) {
clear_pending_tasks_unlocked();
}
}
condition_.notify_all();
for (std::thread &w : workers_) {
if (w.joinable()) {
w.join();
}
}
pool_state_.store(PoolState::Stopped, std::memory_order_release);
}
std::size_t thread_count() const noexcept{ return workers_.size(); };
tp::PoolState state() const noexcept { return pool_state_.load(std::memory_order_acquire); }
std::vector<WorkerState> worker_states_snapshot() const {
const std::size_t n = workers_.size();
std::vector<WorkerState> out(n);
for (std::size_t i = 0; i < n; i++) {
out[i] = worker_states_[i].load(std::memory_order_acquire);
}
return out;
}
void set_exception_handler(ExceptionHandler handler) {
std::unique_lock<std::mutex> lock(exception_handler_mutex_);
exception_handler_ = std::move(handler);
}
bool accepting_tasks() const noexcept {
const PoolState s = pool_state_.load(std::memory_order_acquire);
return s == PoolState::Running || s == PoolState::Paused;
}
void clear_pending_tasks_unlocked(){
while (!tasks_.empty()) {
tasks_.pop();
}
}
void worker_loop(std::size_t index) {
for (;;) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queque_mutex_);
// Stopping 时必须谓词为 true 才会唤醒;若队列已空,旧逻辑返回 false 会导致线程永远睡在 wait() 上,join() 死锁。
condition_.wait(lock, [this]() {
const PoolState ps = pool_state_.load(std::memory_order_acquire);
if (ps == PoolState::Stopping) {
return true;
}
if (!tasks_.empty() && ps == PoolState::Running)
return true;
return false;
});
const PoolState ps = pool_state_.load(std::memory_order_acquire);
if (ps == PoolState::Stopping) {
if (tasks_.empty()) {
worker_states_[index].store(WorkerState::Stopped, std::memory_order_release);
return;
}
if (discard_remaining_tasks_on_stop_) {
worker_states_[index].store(WorkerState::Stopped, std::memory_order_release);
return;
}
}
if (tasks_.empty()) {
continue;
}
task = std::move(tasks_.front());
tasks_.pop();
}
detail::thread_local_worker_index() = index;
worker_states_[index].store(WorkerState::Running, std::memory_order_release);
try {
task();
}
catch (...) {
invoke_exception_handler(index, std::current_exception());
}
worker_states_[index].store(WorkerState::Idle, std::memory_order_release);
}
}
void invoke_exception_handler(std::size_t index, std::exception_ptr ep) {
ExceptionHandler h;
{
std::unique_lock<std::mutex> lock(exception_handler_mutex_);
h = exception_handler_;
}
if (h) {
try {
h(index, ep);
}
catch (...) {
// Swallow exceptions from user handler
}
}
}
private:
std::vector<std::thread> workers_;
std::unique_ptr<std::atomic<WorkerState>[]> worker_states_;
std::queue<std::function<void()>> tasks_;
std::mutex queque_mutex_;
std::condition_variable condition_;
std::atomic<PoolState> pool_state_{ PoolState::Running };
bool discard_remaining_tasks_on_stop_{ false };
std::mutex exception_handler_mutex_;
ExceptionHandler exception_handler_;
};
}