在并发编程场景中,频繁创建 / 销毁线程会带来大量系统开销,线程池作为核心解决方案,能预先创建固定数量的工作线程,统一调度执行异步任务,大幅提升程序性能。
本文基于C++11 标准库实现一个跨平台线程池,全程不依赖第三方库,利用 std::thread、std::mutex、std::condition_variable 等原生组件,保证在 Windows、Linux、macOS 等平台均可直接编译运行。
线程池核心原理
- 构造时初始化指定数量的工作线程,线程启动后进入等待状态,不占用 CPU 资源;
- 提供任务提交接口,将用户任务封装后加入线程安全的任务队列;
- 条件变量实现线程的休眠 / 唤醒机制,有任务时唤醒线程执行,无任务时线程休眠;
- 析构时安全停止线程池,等待所有任务执行完毕后回收线程资源,避免内存泄漏。
案例
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
// C++11 跨平台线程池类
class AsyncThreadPool {
public:
// 构造函数:初始化线程数量
explicit AsyncThreadPool(size_t thread_num) : stop_flag(false) {
// 预创建工作线程
for (size_t i = 0; i < thread_num; ++i) {
workers_.emplace_back([this]() {
worker_loop();
});
}
}
// 禁用拷贝构造和赋值(线程池不允许复制)
AsyncThreadPool(const AsyncThreadPool&) = delete;
AsyncThreadPool& operator=(const AsyncThreadPool&) = delete;
// 析构函数:安全回收线程资源
~AsyncThreadPool() {
// 加锁修改停止标志
std::lock_guard<std::mutex> lock(mtx_);
stop_flag = true;
// 唤醒所有等待的线程
cv_.notify_all();
// 等待所有线程执行完毕并退出
for (std::thread& thread : workers_) {
if (thread.joinable()) {
thread.join();
}
}
}
// 提交任务到线程池(支持任意函数、参数)
template<typename Func, typename... Args>
void submit_task(Func&& func, Args&&... args) {
// 绑定函数与参数,封装为无参可执行任务
using TaskType = void();
std::function<TaskType> task = std::bind(
std::forward<Func>(func),
std::forward<Args>(args)...
);
// 加锁将任务加入队列
std::lock_guard<std::mutex> lock(mtx_);
tasks_.emplace(std::move(task));
// 唤醒一个空闲线程执行任务
cv_.notify_one();
}
private:
// 工作线程主循环
void worker_loop() {
while (true) {
std::unique_lock<std::mutex> lock(mtx_);
// 等待条件:线程池停止 或 有新任务
cv_.wait(lock, [this]() {
return stop_flag || !tasks_.empty();
});
// 线程池停止且无任务,退出线程
if (stop_flag && tasks_.empty()) {
return;
}
// 取出队首任务(移动语义提升性能)
std::function<void()> task = std::move(tasks_.front());
tasks_.pop();
// 解锁后执行任务,避免长时间占用锁
lock.unlock();
// 执行任务
task();
}
}
std::vector<std::thread> workers_; // 工作线程集合
std::queue<std::function<void()>> tasks_;// 线程安全任务队列
std::mutex mtx_; // 互斥锁
std::condition_variable cv_; // 条件变量
bool stop_flag; // 线程池停止标志
};
// 测试主函数
int main() {
// 创建包含5个工作线程的线程池
AsyncThreadPool thread_pool(5);
std::cout << "===== 线程池任务开始执行 =====" << std::endl;
// 提交10个异步任务
for (int idx = 1; idx <= 10; ++idx) {
thread_pool.submit_task([idx]() {
// 打印任务信息:任务ID + 执行线程ID
std::printf("任务 [%d] 正在执行,所属线程ID:%zu\n",
idx, std::hash<std::thread::id>{}(std::this_thread::get_id()));
// 模拟任务耗时(休眠500毫秒)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::printf("任务 [%d] 执行完成\n", idx);
});
}
// 等待所有任务执行完毕(主线程不提前退出)
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "===== 所有任务执行完毕,线程池自动回收 =====" << std::endl;
return 0;
}
代码核心解析
1. 类结构优化
- 重命名为
AsyncThreadPool,更贴合异步任务调度的语义; - 禁用拷贝构造和赋值运算符,避免线程池被错误复制导致程序异常;
- 拆分工作线程逻辑为
worker_loop()私有函数,代码结构更清晰。
2. 线程安全机制
std::mutex保证任务队列的并发访问安全,防止多线程竞争导致数据混乱;std::condition_variable实现线程的高效等待,无任务时线程休眠,不浪费 CPU;wait函数配合谓词,避免虚假唤醒问题,保证线程等待逻辑的可靠性。
3. 任务提交接口
- 模板函数
submit_task支持任意函数、lambda 表达式、类成员函数; - 结合
std::forward完美转发参数,std::move移动语义减少对象拷贝,提升性能; - 每次添加任务后唤醒一个空闲线程,实现任务的实时调度。
4. 安全析构机制
- 析构函数先修改停止标志,再唤醒所有线程;
- 等待所有线程执行完当前任务后退出,确保无任务丢失;
- 检查线程可连接状态,避免重复
join引发崩溃。
运行说明
- 编译要求:支持 C++11 及以上标准的编译器(GCC、Clang、MSVC 均可);
- 跨平台特性:代码无平台相关 API,直接编译运行,无需修改;
- 执行效果:初始化 5 个线程,调度执行 10 个任务,任务并行执行,总耗时约 1 秒(而非 5 秒),充分体现线程池的并发优势。
适用场景
- 服务器并发请求处理
- 批量数据计算 / 文件处理
- UI 界面异步任务(避免卡顿)
- 任何需要频繁执行异步任务的场景
总结
基于 C++11 标准库实现的线程池,轻量、跨平台、无第三方依赖,完美解决了多线程编程中线程管理的痛点。通过预创建线程、任务队列调度、安全资源回收,大幅降低了并发编程的复杂度,同时提升了程序的执行效率。

820

被折叠的 条评论
为什么被折叠?



