版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41035588/article/details/88678011
池是一种用·
空间换时间
的行为,比如我们常见的计算机的
本地缓存
、
代理服务器
、
高速缓存
等都是池或池的变种,它有效的避免了
不同设备之间的频繁切换
,从而提高了运行效率。
一、池的引入
池是一组资源的集合
,有静态、动态资源分配之分。一组资源在服务器启动之初就完全被创建并初始化,称之为静态资源分配。
当服务器运行时,如果需要资源,就可以直接从池中获取,而无需动态分配。因为分配系统资源通常比较耗时,当服务器处理完一个客户连接后,可以将相关资源放回池中,无需调执行系统调用来释放资源,从而避免
了服务器内核态与用户态
的的频繁切换。
二、进程池与线程池
相对于池而言,进程与线程基本上没有区别:在OOP编程中,对象的构造与析构是一个较为复杂的过程,时间消耗较大
,为了提高程序的运行效率,要尽可能减少构造和析构的次数。
因此我们要预先存放一些进程或线程到池,用时在池中取,用完归回给池,免去了创建、删除进程的开销。
·进程池中的所有子进程都运行着相同的代码,并具体相同的属性·
,比如优先级、PGID等。当有新的任务到来时,调用过程如下:
⑴ 主进程使用某种算法(比如随机算法、轮流算法)来主动选择子进程。
⑵ 主进程和所有子进程通过一个共享的工作队列来同步,子进程睡眠在工作队列上,当有新任务到来时,会唤醒一个正在等待任务的拥有接管权的子进程,它从工作队列中取出任务并执行,而其他子进程将继续睡眠。
- 线程池的应用
线程池主要用于
1、需要大量的线程来完成任务,且完成任务的时间比较短。
WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。
因为单个任务小,而任务数量巨大,一个热门网站的点击次数会很多。
但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
2、对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
3、接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。
线程池&&进程池的好处
进程池进程池减少了创建,归还的时间。提高了效率。
三、简单线程池的模拟实现
typedef bool (*Handler)(int sock);
class HttpTask
{
//http请求处理的任务
//包含一个成员socket
//包含一个任务处理的接口
private:
int _cli_sock;
Handler TaskHandler;
public:
//设置任务,也可以先初始化,直接调用任务处理接口,通用不强,所以设计如下
HttpTask():_cli_sock(-1),TaskHandler(NULL){}
void SetHttpTask(int sock,Handler handle)
{
_cli_sock = sock;
TaskHandler = handle;
}
void Run()
{
TaskHandler(_cli_sock);
}
};
class ThreadPool
{
//创建指定数量的线程
//创建一个线程安全的任务队列
//提供任务的入队,出队,线程池销毁/初始化接口
private:
int _max_thr;//池的最大线程数量
int _cur_thr;//当前还有多少线程,确保销毁池的条件
std::queue<HttpTask> _task_queue;
pthread_mutex_t _mutex; //保证数据安全
pthread_cond_t _cond;//保证任务有序
bool _is_stop;//判断是否终止线程
private:
static void *thr_start(void* arg)//完成线程获取任务并执行任务,
{
pthread_detach(pthread_self());
ThreadPool* tp = (ThreadPool*)arg;
tp->QueueLock();
while(tp->QueueEmpty())
{
tp->ThreadWait();
}
HttpTask ht;
tp->PopTaskQueue(ht);
tp->QueueUnLock();
ht.Run();
return NULL;
}
void QueueLock()
{
pthread_mutex_lock(&_mutex);
}
void QueueUnLock()
{
pthread_mutex_unlock(&_mutex);
}
bool IsStop()
{
return _is_stop;
}
void ThreadExit()
{
_cur_thr--;
pthread_exit(NULL);
}
void ThreadWait()
{
if(IsStop())
{
//若要销毁,无需等待
QueueUnLock();
ThreadExit();
}
pthread_cond_wait(&_cond,&_mutex);
}
void ThreadWakeUpOne()
{
pthread_cond_signal(&_cond);
}
void ThreadWakeUpAll()
{
pthread_cond_broadcast(&_cond);
}
bool QueueEmpty()
{
return _task_queue.empty();
}
public:
ThreadPool(int num):_max_thr(num),_cur_thr(0),_is_stop(false){}
~ThreadPool()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond);
}
//完成线程创建,互斥锁/条件变量初始化
bool ThreadPoolInit()
{
pthread_t tid;
for(int i = 0;i<_max_thr;++i)
{
int ret = pthread_create(&tid,NULL,thr_start,(void*)this);
if(ret!=0)
{
LOG("create reror: %s\n",strerror(errno));
return false;
}
_cur_thr++;
}
pthread_mutex_init(&_mutex,NULL);
pthread_cond_init(&_cond,NULL);
return true;
}
//线程安全任务入队
bool PushTaskQueue(HttpTask &tt)
{
QueueLock();
_task_queue.push(tt);
QueueUnLock();
ThreadWakeUpOne();
return true;
}
//线程安全任务出队
bool PopTaskQueue(HttpTask &tt)
{
//因为任务出队在线程接口中调用,但是线程接口在出队前会进行加锁,因此此处不需要加锁
tt = _task_queue.front();
_task_queue.pop();
return true;
}
//线程池销毁
bool ThreadPoolDestroy()
{
if(!IsStop())
{
_is_stop = true;
}
while(_cur_thr>0)
{
ThreadWakeUpAll();//唤醒所所有有任务执行,无任务退出
usleep(1000);
}
return true;
}
};
参考博客:
进程池与线程池