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

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











