代码仓库:https://gitee.com/tgwTTT/linux-learning-dai/tree/master/ThreadPool2
引言
在现代软件开发中,多线程编程是提升程序性能的重要手段。然而,频繁创建和销毁线程会带来显著的系统开销。线程池(Thread Pool)作为一种高效的并发设计模式,通过预先创建并管理一组线程,实现了线程的复用,从而解决了这一问题。本文将系统性地介绍线程池的基本概念、核心组件,并通过关键代码片段解析其工作原理,帮助初学者建立清晰的理解。
一、线程池的基本概念
线程池是一种管理多个线程执行任务的机制。其核心思想是资源池化:在程序启动时创建固定数量的线程,并将它们置于等待状态。当有任务需要执行时,线程池从池中分配一个空闲线程来处理任务,任务完成后线程返回池中,等待下一个任务。这种方式避免了线程的重复创建与销毁,显著降低了系统开销。
线程池主要解决了以下问题:
- 性能瓶颈:线程的创建和销毁涉及系统调用,消耗CPU和内存资源。
- 资源失控:无限制地创建线程可能导致系统资源耗尽。
- 编程复杂性:手动管理线程的生命周期容易出错。
二、核心组件与工作流程
一个典型的线程池包含四个核心组件:线程集合、任务队列、互斥锁和条件变量。它们协同工作,确保任务被安全、高效地处理。
1. 互斥锁(Mutex)与条件变量(Condition Variable)
互斥锁用于保护共享资源,防止多个线程同时访问导致数据竞争。条件变量则用于线程间的同步,实现“等待-通知”机制。二者结合使用,是构建线程池的基础。
// 互斥锁类,用于保护共享数据
class Mutex {
public:
Mutex() { pthread_mutex_init(&_mutex, nullptr); }
~Mutex() { pthread_mutex_destroy(&_mutex); }
void Lock() { pthread_mutex_lock(&_mutex); }
void Unlock() { pthread_mutex_unlock(&_mutex); }
pthread_mutex_t* GetPthreadMutex() { return &_mutex; }
private:
pthread_mutex_t _mutex;
};
// 条件变量类,用于线程同步
class Cond {
public:
Cond() { pthread_cond_init(&_cond, nullptr); }
~Cond() { pthread_cond_destroy(&_cond); }
void Wait(Mutex* mutex) {
pthread_cond_wait(&_cond, mutex->GetPthreadMutex());
}
void Signal() { pthread_cond_signal(&_cond); }
void Broadcast() { pthread_cond_broadcast(&_cond); }
private:
pthread_cond_t _cond;
};
2. 任务队列与线程处理逻辑
任务队列是一个线程安全的队列,用于存放待处理的任务。工作线程从队列中取出任务并执行。
void HandlerTask() {
Task task;
while (true) {
LockGuard lock(_mutex);
// 使用while循环防止虚假唤醒
while (_taskq.empty() && _isrunning) {
_cond.Wait(&_mutex);
}
// 检查线程池是否停止
if (!_isrunning && _taskq.empty()) {
break;
}
// 取出任务
task = std::move(_taskq.front());
_taskq.pop();
} // LockGuard析构,自动释放锁
// 在锁外执行任务,避免阻塞其他线程
task();
}
3. 任务提交接口
bool Enqueue(const Task& t) {
LockGuard lock(_mutex);
if (!_isrunning) {
return false; // 线程池已停止
}
_taskq.push(t);
_cond.Signal(); // 唤醒一个等待的线程
return true;
}
今天的更新就到这里,如有错误欢迎指出!!
评论
还没有任何评论,你来说两句吧!