目录
一.概念

线程池:见名知义,就是多个线程构成的集合。其中线程的个数是确定的,并不是固定的。
为什么要有线程池?
如果每次都只创建一个线程,首先当用户请求过多时,每次都需要创建一个线程,创建线程需要时间和调度开销,这样会影响缓存的局部性和整体的性能。其次线程池linux,如果无上限一直创建线程,还会导致CPU的过分调度。
线程池已经创建好了一定数量的线程,等待着分配任务,这样避免了处理任务时的线程创建和销毁。线程池里线程个数确定,能够保证内核的充分利用,还能防止过分调度。
线程池中可用线程数量取决于可用额并发处理器,处理器内核,内存,网络socket等的数量。
线程池的应用场景:
需要大量的线程来完成任务,且完成人物的时间比较短。比如:WEB服务器完成网页请求这样的任务,因为当个任务小,并且任务量巨大,你可以想象一个热门网站的请求次数。但是对于长时间的任务,线程池的优先就不明显了。比如:一个Telnet连接请求,因为Telnet会话时间比线程创建时间大多了。对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。接收突发性的大量请求,但是不至于使服务器因此产生大量线程应用。突发性大量客户请求,在没有线程池的情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量的线程可能使内存到达极限,出现错误。二.线程池实现
线程池实际也是一个生产者消费者模型,接收任务,往任务队列中放任务的是生产者,从任务队列中拿任务并执行的是消费者。
主线程是生产者,用来接收任务和放任务。
int main(){
mythreadpool *tp=new mythreadpool();
tp->threadinit();
int count=10;
while(1){
//sleep(1);
int x=rand()+1;
int y=rand()%20+1;
Task t(x,y);
//put里有加锁,不需要加锁了
tp->Put(t);
std::cout<<"put Task done..."<ThreadQuit();
delete tp;
return 0;
}
线程池中的线程的创建封装在类中,线程获得任务的函数就会成为类的成员函数,在C++中,类的成员函数会隐含一个this指针,导致函数有两个参数,但是只能由一个参数,所以要对线程获得任务的函数加一个static,并且需要将调用对象的this指针作为参数传进来,不然就不能调用其它成员函数。
//成员函数,由this指针作为参数,
//线程函数,只能有一个参数,所以要加static
static void *handler(void *arg){
mythreadpool *p_this = (mythreadpool *)arg;
while(1){
p_this->ThreadLock();
//不退出,没有数据要等待
while(!(p_this->_quit)&&(p_this->IsEmpty())){
p_this->ThreadWait();
}
//退出没有数据,直接退出
//退出有数据,还需要执行任务
if(p_this->_quit&&p_this->IsEmpty()){
p_this->ThreadUnlock();
p_this->ThreadExit();
}
//执行任务
Task t;
p_this->Get(t);
p_this->ThreadUnlock();
int res=0;
res = t.Add();
std::cout<
注意如果服务还在运行,线程不退出,生产者不能有等待的情况,如果生产者等待,用户链接不上了。
线程退出:
设置一个标志位quit,起始设置false,不退出。当需要退出时将quit设置为true。
此时可能会有线程在等待,需要全部唤醒线程。
当线程还没有完全退出时,需要生产者等待。
当还有任务时,需要线程继续执行任务,执行完任务后才能退出。
总代码:
#pragma once
#include
#include
#include
#include
#define NUM 5
struct Task{
Task(){};
Task(int x, int y){
_x=x;
_y=y;
}
~Task(){};
int _x;
int _y;
int Add(){
return _x + _y;
}
};
class mythreadpool{
private:
void ThreadLock(){
pthread_mutex_lock(&_lock);
}
void ThreadUnlock(){
pthread_mutex_unlock(&_lock);
}
void ThreadWait(){
pthread_cond_wait(&_cond, &_lock);
}
void ProductorWait(){
pthread_cond_wait(&_pcond, &_lock);
}
void ProductorSignal(){
pthread_cond_signal(&_pcond);
}
void ThreadSignal(){
pthread_cond_signal(&_cond);
}
//唤醒全部线程
void ThreadSignalAll(){
pthread_cond_broadcast(&_cond);
}
bool IsEmpty(){
return _q.empty();
}
//退出线程
void ThreadExit(){
_numthread--;
printf("%lu is exit\n",pthread_self());
ProductorSignal();
pthread_exit(0);
}
public:
mythreadpool(size_t num = NUM)
:_numthread(num)
,_quit(false)
{}
//成员函数,由this指针作为参数,
//线程函数,只能有一个参数,所以要加static
static void *handler(void *arg){
mythreadpool *p_this = (mythreadpool *)arg;
while(1){
p_this->ThreadLock();
//不退出,没有数据要等待
while(!(p_this->_quit)&&(p_this->IsEmpty())){
p_this->ThreadWait();
}
//退出没有数据,直接退出
//退出有数据,还需要执行任务
if(p_this->_quit&&p_this->IsEmpty()){
p_this->ThreadUnlock();
p_this->ThreadExit();
}
//执行任务
Task t;
p_this->Get(t);
p_this->ThreadUnlock();
int res=0;
res = t.Add();
std::cout< _q;//任务队列
size_t _numthread;//线程个数
pthread_mutex_t _lock;//锁
pthread_cond_t _cond;//消费者在此等待
pthread_cond_t _pcond;//生产者在此等待
bool _quit;//是否退出
};
#include"mythreadpool.hpp"
int main(){
mythreadpool *tp=new mythreadpool();
tp->threadinit();
int count=10;
while(1){
//sleep(1);
int x=rand()+1;
int y=rand()%20+1;
Task t(x,y);
//put里有加锁,不需要加锁了
tp->Put(t);
std::cout<<"put Task done..."<ThreadQuit();
delete tp;
return 0;
}
(编辑:成都站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|