1. 为什么需要线程池与单例模式的结合
在Linux服务器开发中,线程池几乎是每个高性能服务端程序的标配组件。我曾在处理一个在线交易系统时,因为频繁创建销毁线程导致CPU负载飙升到90%以上,直到引入线程池才将负载稳定在30%左右。但随之而来的是另一个问题——多个模块各自创建线程池导致系统线程数失控。
这就是单例模式的价值所在。通过确保整个进程内只有一个线程池实例,我们既能复用线程资源,又能避免无节制的线程创建。但多线程环境下实现单例并非易事,我曾亲眼目睹一个双重检查锁(DCLP)实现不当导致的内存泄漏事故。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 线程池基础架构设计
2.1 核心组件拆解
一个工业级线程池至少包含以下组件:
- 任务队列(我推荐使用
std::queue+互斥锁而非无锁队列,后者调试成本太高) - 工作线程组(数量建议设置为CPU核心数×2+2)
- 条件变量(用于线程唤醒,注意虚假唤醒问题)
- 关闭标志(优雅停机必备)
cpp复制class ThreadPool {
private:
std::queue<std::function<void()>> tasks;
std::vector<std::thread> workers;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
2.2 任务提交接口设计
任务提交是使用频率最高的接口,我习惯提供三种形式:
- 普通函数指针
- Lambda表达式
- std::function对象
关键技巧是使用模板推导+完美转发:
cpp复制template<class F>
void enqueue(F&& f) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
3. 单例模式的线程安全实现
3.1 经典DCLP方案及其陷阱
教科书式的双重检查锁实现:
cpp复制stati
