什么是线程池?
所有的池化技术,都可以看作一种缓冲区,举个生活中的例子,蓄水池、大坝之类。大家想想这些蓄水池的作用是什么?
而线程池就是组织一批线程,在适当时机,按分配顺序去依次完成到来的任务。
为什么有线程池?
- 线程过多会带来调度开销,进而影响缓存局部性和整体性能。
- 而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。
- 这避免了在处理短时间任务时创建与销毁线程的代价。(指PCB)
- 线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
线程池的应用场景:
- 需要大量的线程来完成任务,且完成任务的时间比较短。
- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误.
模拟实现线程池
#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>
#include<unistd.h>
template <class T1>
class mask
{
public:
mask(){}
mask(T1 a,T1 b)
:data1(a),data2(b)
{}
T1 Add()
{
T1 rel=data1+data2;
std::cout <<"thread is[" << pthread_self() << "] mask run ... done: base# " ;
std::cout<<data1<<" + "<<data2<<" = "<<rel<<std::endl;
return rel;
}
protected:
T1 data1;
T1 data2;
};
template <class T>
class pthread_pool
{
public:
pthread_pool(int maxnum=6,bool q=false)
:_poolmax(maxnum),quit(q)
{}
~pthread_pool()
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&empty);
}
void push(T& in)
{
lock_queue();
pool.push(&in);
unlock_queue();
//notice_consumer();
notice_all_consumer();
}
void get_rel(T& out) //这里不再需要上锁,因为获取数据的地方在线程调用的Run里,线程已经在Run函数里上好锁排好队了。
{
//lock_queue();
out=*pool.front();
pool.pop();
//unlock_queue();
}
static void* Run(void* arg) //由于C++成员函数第一个参数是隐藏的this指针,不符合pthread_create的第三个函数指针的参数,所以定义为静态成员函数去掉this指针。同时传参传this指针,方便访问使用成员
{
pthread_pool* this_p=(pthread_pool*)arg;
while(!this_p->quit)
{
usleep(2500);
this_p->lock_queue();
while(!this_p->quit && this_p->cond_empty()) //当线程池为空时,线程都在cond_empty这个条件变量和锁内部,成队列等待,
//唤醒可以一群唤醒(惊群效应)pthread_cond_broadcast(),也可以一个一个唤醒pthread_cond_signal()
{
this_p->wait_consumer();
}
T m;
if(!this_p->quit && !this_p->pool.empty())
{
this_p->get_rel(m);
}
this_p->unlock_queue();
m.Add();
}
return;
}
void quit_pthread_pool()
{
if(!pool.empty())
{
std::cout<<"仍有任务在运行! "<<std::endl;
return ;
}
quit =true;
notice_all_consumer();
}
void Init()
{
pthread_mutex_init(&lock,nullptr);
pthread_cond_init(&empty,nullptr);
pthread_t t;
for(int i=0;i<_poolmax;i++)
{
pthread_create(&t,nullptr,Run,this);
}
}
protected:
std::queue<T*> pool;
int _poolmax;
pthread_mutex_t lock;
pthread_cond_t empty;
bool quit;
private:
void lock_queue()
{
pthread_mutex_lock(&lock);
}
void unlock_queue()
{
pthread_mutex_unlock(&lock);
}
bool cond_empty()
{
return pool.empty();
}
void wait_consumer()
{
pthread_cond_wait(&empty,&lock);
}
void notice_consumer()
{
pthread_cond_signal(&empty);
}
void notice_all_consumer()
{
pthread_cond_broadcast(&empty);
}
};
#include"pthread_pool.hpp"
#include<unistd.h>
using namespace std;
int main()
{
pthread_pool<mask<int>> pp(5);
pp.Init();
int count=30;
while(count--)
{
int left=random()%103;
int right=random()%103;
mask<int> m(left,right);
cout<<left<<" + "<<right<<" = ? "<<endl;
pp.push(m);
usleep(1250);
}
return 0;
}