C++线程池|解决死锁、崩溃、丢任务所有痛点

手写工业级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_;
	};
}
相关推荐
天天进步20151 小时前
魔音漫创源码解析:状态管理——复杂长链路下的状态同步:Zustand 在多面板协作中的应用
开发语言·架构
知识领航员2 小时前
2026年推荐6个AI音乐工具
java·人工智能·python·eclipse·django·php·pygame
mfxcyh2 小时前
如何把对象数据转化为数组
java·服务器·前端
念越2 小时前
从网络基础到Socket编程:TCP/UDP原理 + Java实战详解
java·网络·tcp/ip·udp
古城小栈2 小时前
langchain-rust:高性能Rust LLM应用开发实战
开发语言·rust·langchain
我是无敌小恐龙3 小时前
Java基础入门Day10 | Object类、包装类、大数/日期类、冒泡排序与Arrays工具类 超详细总结
java·开发语言·数据结构·算法·贪心算法·排序算法·动态规划
极客先躯3 小时前
高级java每日一道面试题-2025年12月07日-实战篇[Dockerj]-Docker daemon 的配置文件在哪里?常用的配置项有哪些?
java·docker·配置文件的实际位置·配置文件的格式规则·常用配置项全景与分类·配置如何生效·daemon 配置折射架构思维
云烟成雨TD3 小时前
Spring AI Alibaba 1.x 系列【49】状态图运行时引擎:CompiledGraph 源码解析
java·人工智能·spring
yuanyuan2o23 小时前
从最小项目开始的 CMake 教程
c语言·开发语言·arm开发·c++·makefile·make·cmake