线程池
基本概念
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个 线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不 仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内 存、网络sockets等的数量;
线程池的工作机制:
在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部寻找是否有空闲的线程,如果有,则将任务交给某个空闲的线程。
一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务
线程池的应用场景
需要大量的线程来完成任务,且完成任务的时间比较短。
WEB服务器完成网页请求这样的任务,使 用线程池技术是非常合适的。
因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。
但对于 长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大 多了。
对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。
突发性大量客户请求,在没 有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程 可能使内存到达极限,出现错误.
实现一个线程池
#include <iostream>
#include <queue>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define MAX_THR 10
#define MAX_QUE 5
typedef bool (*task_callback)(int data);//定义一个函数指针,规定对数据的处理
bool deal_data(int data){
srand(time(NULL));
int n = rand() % 5;
std::cout<<"thread:"<<pthread_self()<<"deal_data"<<data<<"sleep"<<n<<std::endl;
return true;
}
//执行的任务
class Task{
public:
Task(int data = 0):
_data(data);
{}
public:
void SetTask(int data,task_callback handle){
_data = data;
_handle = handle;
}
bool Run(){
return _handle(_data);
}
private:
int _data;
task_callback _handle;
};
class ThreadPool{
public:
~ThreadPool(){
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_con);
pthread_cond_destroy(&_cond_pro);
}
//构造函数没有返回值然而 线程创建不一定成功
bool ThreadInit(int max_thr = MAX_THR,int max_que = MAX_QUE) {
_quit_flag = false;
_max_thr = max_thr;
_cur_thr = max_thr;
_capacity = max_que;
pthread_mutex_init(&_mutex,NULL);
pthread_cond_init(&_cond_con,NULL);
pthread_cond_init(&_cond_pro,NULL);
int ret;
//创建线程
pthread_t tid;
for(int i = 0;i < _max_thr;i++){
pthread_create(&tid,NULL,thr_start,(void*)this);
if(ret != 0)
return false;
pthread_detach(tid);
}
return true;
}
bool PushTask(Task& task){
//当线程要退出时不再插入任务
if(_quit_flag == true){
return false;
}
QueueLock();
while(QueueIsFull()){
ProWait();
}
_quene.push(task);
ConWeakup();
QueueUnlock();
return true;
}
void TaskPop(Task& task){
QueueLock();
while(QueueIsEmpty()){
ConWait();
}
task = _quene.front();
_quene.pop();
ProWeakup();
QueueUnlock();
}
void TreadQuit(){
if(_quit_flag != true){
_quit_flag = true;
}
while(1){
//退出之前有可能大量的线程陷入阻塞状态不能退出需要唤醒
ConWeakupAll();
sleep(1);
}
}
private:
bool QueueIsEmpty(){
return _quene.empty();
}
bool QueueIsFull(){
return _quene.size()==_capacity;
}
void QueueLock(){
pthread_mutex_lock(&_mutex);
}
void QueueUnlock(){
pthread_mutex_unlock(&_mutex);
}
void ConWait(){
if(_quit_flag == true){
//在线程退出的地方都要解锁
QueueUnlock();
std::cout<<"thread:"<<pthread_self()<<"exit"<<std::endl;
_cur_thr--;
pthread_exit(NULL);
}
pthread_cond_wait(&_cond_con,&_mutex);
}
void ConWeakup(){
pthread_cond_signal(&_cond_con);
}
void ConWeakupAll(){
pthread_cond_broadcast(&_cond_con);
}
void ProWait(){
pthread_cond_wait(&_cond_pro,&_mutex);
}
void ProWeakup(){
pthread_cond_signal(&_cond_pro);
}
//这里不能有this指针不满足函数要求所以加static修饰
static void* thr_start(void* arg){
ThreadPool* pool = (ThreadPool*)arg;
while(1){
pool->QueueLock();
Task task;
pool->TaskPop(task);
pool->QueueUnlock();
task.Run();
}
}
private:
int _max_thr;//最大线程数量
int _cur_thr;//当前线程数量
int _quit_flag;//退出标志
int _capacity;//队列的最大数量
std::queue<Task> _quene;
pthread_mutex_t _mutex;
pthread_cond_t _cond_pro;
pthread_cond_t _cond_con;
};
int main(){
ThreadPool pool;
pool.ThreadInit();
Task task[10];
for(int i = 0;i < 10; ++i){
task[i].SetTask(i,deal_data);
pool.PushTask(task[i]);
}
pool.TreadQuit();
return 0;
}