线程池
1.概念:
顾名思义就是许多线程的一个集合。
2.线程池的意义:
虽然线程是轻量级的进程,创建的开销比进程小,但是,频繁的创建与销毁线程也会得不偿失,导致线程的创建与销毁所占的时间成本远大于任务处理的时间成本;因此我们将线程创建后不再销毁而是先放在一起,任务一旦分配就直接进行处理,任务执行完毕,统一销毁。这样就大大提高了任务处理的效率。
3.特点:
(1)线程池中的线程全是消费者线程
(2)线程池中的线程数目是由上限的--为并避免出现峰值压力,导致资源瞬间被耗尽
4.实现:
5.代码实现:
//实现一个线程池:
#include <iostream>
#include <stdlib.h>
#include <thread>
#include <queue>
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include <sstream>
#include <time.h>
using std::endl;
#define MAX_THREAD 5 //最大线程数量5
#define MAX_QUEUE 10 //最大结点数量10
typedef void(*handler_t)(int);
class MyTask{
private:
int _data; //任务的数据类型--整型
handler_t _handler; //数据的处理方式--函数指针
public:
MyTask(int data,handler_t handler):
_data(data),
_handler(handler){}
//任务布置
void SetTask(int data,handler_t handler){
_data = data;
_handler = handler;
return;
}
//任务处理的函数
void Run(){
return _handler(_data);
}
};
class ThreadPool{
private:
std::queue<MyTask> _queue; //任务队列
int _capacity; //队列所能容纳的最大结点数量
pthread_mutex_t _mutex; //互斥锁
pthread_cond_t _cond_pro; //条件变量--生产者
pthread_cond_t _cond_con; //条件变量--消费者
int _thr_max; //线程池内最大线程数量
bool _quit_flag; //标志位--标记是否还有线程
int _thr_cur; //记录当前的线程数量--防止单词唤醒有遗漏的线程
std::vector<std::thread> _thr_list; //管理线程的列表
private:
void thr_start(){
//出队拿数据--再处理数据
while(1){
pthread_mutex_lock(&_mutex);
while(_queue.empty()){
//队空,并且没有任务--退出
if(_quit_flag == true){
//在任意线程退出的情况下都要进行解锁
std::cout << "thread exit" << pthread_self() << endl;
pthread_mutex_unlock(&_mutex);
_thr_cur--;
return;
//pthread_exit(NULL);
}
pthread_cond_wait(&_cond_con,&_mutex);
}
//有数据
MyTask tt = _queue.front();
_queue.pop();
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_pro);
//任务处理要放在解锁之后,否则会造成同一时间只有一个线程在处理任务;
//必须是可重入函数
tt.Run();
}
return;
}
public:
//构造函数:初始化所有成员变量
ThreadPool(int maxq = MAX_QUEUE, int maxt = MAX_THREAD):
_capacity(maxq),
_thr_max(maxt),
_thr_list(maxt),
_quit_flag(false){
pthread_mutex_init(&_mutex,NULL);
pthread_cond_init(&_cond_pro,NULL);
pthread_cond_init(&_cond_con,NULL);
}
//对所有线程进行初始化
bool PoolInit(){
_thr_cur = 0;
for(int i = 0; i < _thr_max; ++i){
_thr_list[i] = std::thread(&ThreadPool::thr_start,this);
_thr_cur++;
//直接分离线程,处理完毕直接退出,资源自动释放,不必再等待
_thr_list[i].detach();
}
//添加任务--本质上就是入队操作
bool AddTask(MyTask& tt){
//入队
pthread_mutex_lock(&_mutex);
while(_queue.size() == _capacity){
//入队--生产者入队,
pthread_cond_wait(&_cond_pro,&_mutex);
}
_queue.push(tt);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_con);
return true;
}
bool PoolStop(){
pthread_mutex_lock(&_mutex);
_quit_flag = true;
//为防止改成真的时候,有些线程已经陷入了休眠,
//则不会再去thr_start()里边去判断标志位是否为真,则线程不会退出
//故需要唤醒线程
//为防止线程唤醒之时在处理任务,唤醒之后现入阻塞
//则需要判断当前线程数量,如果还有线程就广播唤醒
while(_thr_cur > 0){
pthread_cond_broadcast(&_cond_con);
usleep(1000);
}
return true;
}
//析构函数:销毁所变量、生产者与消费者的条件变量
~ThreadPool(){
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_pro);
pthread_cond_destroy(&_cond_con);
}
};
void test(int data){
srand(time(NULL));
int nsec = rand() % 5;
std::stringstream ss;
ss << "thread" << pthread_self() << "processing data";
ss << data << "and sleep" << nsec << "sec\n";
//ss.str()获取字符串
std::cout << ss.str();
sleep(nsec);
return;
}
int main(){
ThreadPool pool;
pool.PoolInit();
for(int i = 0; i < 10; ++i){
MyTask tt(i, test);
pool.AddTask(tt);
}
pool.PoolStop();
return 0;
}