1. 为什么我们需要线程池?
在Linux服务器开发中,多线程编程是家常便饭。但直接使用原生线程接口会遇到几个典型问题:
-
线程创建销毁开销大:每次
pthread_create都需要系统调用,内核要为线程分配栈空间、初始化线程控制块等资源。实测在4核8G机器上,创建1000个空线程需要约200ms。 -
线程数量失控风险:假设每个请求开一个线程,当突发大流量时(比如秒杀活动),可能瞬间创建上千线程,导致系统资源耗尽。
-
响应延迟问题:当任务到达时才创建线程,用户需要等待线程初始化完成才能开始处理,增加了响应时间。
实际案例:某电商系统在促销时直接为每个订单创建线程,高峰期线程数突破3000,导致CPU大量时间消耗在线程上下文切换上,最终系统崩溃。
2. 线程池核心设计思路
2.1 工厂模型类比
想象一个快递仓库:
- 固定工人 = 线程池中的工作线程(比如5个)
- 快递货架 = 任务队列(先进先出)
- 快递包裹 = 待处理的任务(函数对象)
- 值班经理 = 线程池管理者(负责启停和监控)
2.2 关键技术组件
| 组件 | 作用 | 对应实现 |
|---|---|---|
| 任务队列 | 缓冲待处理任务 | std::queue<T> |
| 互斥锁 | 保护队列并发访问 | pthread_mutex_t |
| 条件变量 | 线程休眠与唤醒 | pthread_cond_t |
| 工作线程 | 实际执行单元 | std::vector<Thread> |
| 优雅退出标志 | 安全关闭控制 | bool is_running |
3. 关键模块实现详解
3.1 线程安全队列
cpp复制template<typename T>
class TaskQueue {
public:
void Push(const T& task) {
LockGuard lock(mutex_);
queue_.push(task);
cond_.NotifyOne(); // 有新任务时唤醒一个线程
}
