线程池
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,即在程序初始化时,创建一定数量的线程(又最大限制),从任务队列中获取任务,进行处理
线程池=至少一个线程+任务队列
作用:
1.避免为大量请求创建线程,导致瞬间资源耗尽程序崩溃的问题
2.避免大量线程频繁创建销毁所带来的时间成本
线程池的应用场景:
1.需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线 程池技术是非常合适的。因为单个任务小,而任务数量巨大,但对于长时间的任 务,比如一个Telnet这样会话时间比线程的创建时间长的多的任务,线程池的优点就不明显了
2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用
线程池的实现:
1.创建固定数量的线程,创建线程安全的任务队列
2.循环从任务队列中获取任务对象,执行任务对象中的任务接口和数据
代码框架
//任务类
typrdef void(*handler_t)(int data)//函数指针
class Task{
int data; //要处理的数据
handler_t_handle; //处理数据的函数
setdata(int data,handler_t func){
_data=data;
_handler=func;
}
run(){
_handler(data);
}
}
//线程池类
class threadpool{
int thr_max; //线程的最大个数
std:queue<Task> _task_queue; //实现线程安全的任务队列(同生产者与消费者模型)
pthread_mutex_t_mutex; //互斥锁
pthread_cond_t _pro_cond; //生产者队列
pthread_cond_t _con_cond; //消费者队列
TaskPush(Task &t); //入队列
TaskPop(Task &t); //出队列
void *thr_start(void *arg); //线程函数用来处理任务
}
简单实现
#include <iostream>
#include <queue>
#include <pthread.h>
typedef void (*handler_t)(int data);//定义函数指针
class Task
{
public:
void SetTask(int data, handler_t handler){//将数据和处理函数传入
_data = data;
_handler = handler;
}
//给线程池的所有线程提供统一的接口
void Run(){
_handler(_data);
}
private:
int _data;
handler_t _handler;
};
#define THR_MAX 5
class ThreadPool
{
public:
//构造函数
ThreadPool(int max==THR_MAX)
: _thr_max(max)
,_cur_thr(max)
,_quit_flag(false)
{
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_con_cond, NULL);
pthread_cond_init(&_pro_cond, NULL);
}
~ThreadPool() {
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_con_cond);
pthread_cond_destroy(&_pro_cond);
}
//创建线程
bool PoolInit() {
int ret;
pthread_t tid;
for (int i = 0; i < _thr_max; i++) {
ret = pthread_create(&tid, NULL, thr_start,(void*)this);
if (ret != 0) {
std::cerr << "thread create error\n";
return false;
}
pthread_detach(tid);//将退出的线程的资源自动回收
}
return true;
}
//入队任务
bool TaskPush(Task &t) {
QueueBlock();
_task_queue.push(t);
ConsumerWakeUp();//唤醒消费者
QueueUnblock();
return true;
}
//出队任务
bool TaskPop(Task &t) {
//获取队首任务并出队
t = _task_queue.front();
_task_queue.pop();
return true;
}
//线程入口函数
static void *thr_start(void *arg) {
ThreadPool *pool = (ThreadPool*)arg;
while(1){
pool->QueueBlock();
//任务队列为空,等待在生产者队列
while (pool->QueueIsEmpty()) {
pool->ConsumerWait();
}
Task t;
pool->TaskPop(t);
pool->QueueUnblock();
//需要先解锁再处理任务,否则其他线程无法处理任务,丧失并发性
t.Run();
}
return NULL;
}
//线程池的退出,等所有任务处理完毕才退出,不能直接return 0
void PoolQuit(){
QueueBlock();
if(_quit_flag==false){
_quit_flag==true;
}
QueueUnblock();
while(_cur_thr>0){
ConsumerWakeUp();
}
}
public:
void QueueBlock(){
pthread_mutex_lock(&_mutex);
}
void QueueUnblock(){
pthread_mutex_unlock(&_mutex);
}
//线程陷入等待之前需要先判断用户是否要退出
void ConsumerWait(){
if(_quit_flag==true){
_cur_thr--;
pthread_mutex_unlock(&_mutex);
pthread_exit(NULL);
}
pthread_cond_wait(&_con_cond,&_mutex);
}
void ConsumerWakeUp(){
pthread_cond_signal(&_con_cond);
}
bool QueueIsEmpty(){
return _task_queue.empty();
}
private:
int _thr_max;//最大线程数量
std::queue<Task> _task_queue;//任务队列
bool _quit_flag;//设置一个标志,在flag为true时,所有线程被唤醒并退出
int _cur_thr;//当前线程池的线程数量
pthread_mutex_t _mutex;
pthread_cond_t _pro_cond;
pthread_cond_t _con_cond;
};
int main ()
{
pool.poolQuit();
return 0;
}