C++线程池讲解及Linux环境代码示例
1. 线程池是什么?
线程池是一种基于多线程的并发设计模式,用来减少在应用程序中创建和销毁线程的频率。它通过维护多个线程待命,来处理多个任务,这些线程可以循环利用,以避免频繁的创建线程的开销。这些线程在创建线程池时生成,并在线程池销毁时终止。
2. 为什么要使用线程池?
使用线程池的主要优点包括:
- 性能提高:通过重复使用现有线程减少线程创建和销毁的开销。
- 资源控制:允许程序更好地管理资源使用,例如限制最大并发线程数,从而避免过多的线程耗尽系统资源。
- 更简单的线程管理:线程的生命周期管理被集中,简化了编程模型。
3. 线程池的组成部分
线程池主要由以下几个部分组成:
- 工作线程:这些是线程池中的线程,负责执行任务。
- 任务队列:一个线程安全的队列,用于存储待处理的任务。
- 锁(例如互斥锁):用于控制对任务队列的并发访问。
- 条件变量:用来阻塞线程直到有任务可执行,或通知线程任务已可执行。
- 管理机制:负责处理线程的创建、销毁和健康状态等。
4. 使用线程池时需要注意的事项
- 适当配置:线程池的大小应根据系统资源和需求适当配置。
- 避免长时间任务:长时间运行的任务可能会占用所有可用线程,导致线程池饱和。
- 异常处理:确保任务中的异常被妥善处理,避免异常影响线程池中的其他任务。
- 线程同步:在任务中合理使用同步机制,避免死锁和资源竞争问题。
5. 一个安全的线程池代码示例(C++98/03标准)
以下是一个简单的线程池实现示例,不使用 C++11 或更高版本的特性,仅使用 POSIX 线程库。
threadpool.cpp
#include <pthread.h>
#include <queue>
#include <iostream>
#include <stdexcept>
#include <unistd.h>
class ThreadPool {
public:
ThreadPool(size_t num_threads) : stopping(false)
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
for (size_t i = 0; i < num_threads; ++i)
{
pthread_t worker_thread;
pthread_create(&worker_thread, NULL, worker, this);
workers.push_back(worker_thread);
}
}
~ThreadPool()
{
pthread_mutex_lock(&lock);
stopping = true;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
for (size_t i = 0; i < workers.size(); ++i)
{
pthread_join(workers[i], NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
}
void enqueue(void (*task)())
{
pthread_mutex_lock(&lock);
tasks.push(task);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
private:
static void* worker(void* arg)
{
ThreadPool* pool = (ThreadPool*)arg;
while (true) {
pthread_mutex_lock(&pool->lock);
while (pool->tasks.empty() && !pool->stopping) {
pthread_cond_wait(&pool->cond, &pool->lock);
}
if (pool->stopping && pool->tasks.empty()) {
pthread_mutex_unlock(&pool->lock);
break;
}
/*
void: 表示函数没有返回值。
(*task): task 是一个指针,* 表明这是一个指向函数的指针。
(): 表示函数不接受任何参数。
*/
void (*task)() = pool->tasks.front();
pool->tasks.pop();
pthread_mutex_unlock(&pool->lock);
task(); // 执行任务
}
return 0;
}
private:
pthread_mutex_t lock;
pthread_cond_t cond;
std::queue<void (*)()> tasks;
std::vector<pthread_t> workers;
bool stopping;
};
void taskFunction() {
std::cout << "Executing Task" << std::endl;
}
int main() {
ThreadPool pool(4);
pool.enqueue(taskFunction);
pool.enqueue(taskFunction);
pool.enqueue(taskFunction);
pool.enqueue(taskFunction);
sleep(1); // 等待任务完成
return 0;
}
6. 代码解释
这段代码实现了一个基本的线程池,其中包含:
- 一个任务队列和一组工作线程。
- 使用互斥锁和条件变量来控制对任务队列的访问和线程的同步。
- 工作线程从队列中取出任务并执行,当没有任务时会等待。
- 析构函数中停止所有工作线程,并清理 POSIX 线程相关资源。
7. 编译
g++ -o threadpool threadpool.cpp -lpthread
8. 输出代码运行结果
./threadpool
程序创建了一个线程池并提交了四个任务,每个任务简单地输出 “Executing Task”。由于使用了 sleep(1)
,主线程会等待足够的时间让所有任务执行完毕。可以看到输出中四次 “Executing Task” 的结果。
注意
这个实现较为简单,主要用于演示目的。在生产环境中,建议使用成熟的线程池库,如 Boost.Asio 的线程池功能,或者升级到支持 C++11 或更高版本的编译器,使用 std::thread 和相关的高级特性。
(后面会更新C++11版本的线程池示例)