之前写http服务器的时候,用到了线程池去完成服务器的创建,之前的线程池实现参照:https://blog.youkuaiyun.com/tonglin12138/article/details/94035217。
但是之前给出的实现有一个最大的缺陷就在于线程数量一开始就是给死的。我们在线程池初始化的时候直接一次性的创建了一批线程。其实更加完善的做法应该是模拟实现一个动态的线程池出来:当当前处于工作状态的线程数量与创建的线程数量一样的时候,我们应该再创建一些线程;当处于休眠状态线程的数量大于我们设置的最大线程休眠数量的时候,我们应该回收一部分线程。从而达到实现出一个动态的线程池的目的。
1.动态线程池的实现思想
1.之前的线程池类的私有成员作出改变:
class ThreadPool
{
private:
//int thread_total_num;
int thread_free_num; //最大休眠线程数
queue< Task > task_queue;
pthread_t *thread_id;
int thread_max_num; //线程池容纳最大线程数
int thread_cur_num; //当前线程池存放的线程数
int thread_cur_task_num //当前工作的线程数
pthread_mutex_t lock;
pthread_cond_t cond;
bool isquit;
};
2.扩容:在向任务队列中push任务之后,进行判断:
if ((thread_cur_task_num == thread_cur_num) &&
(thread_cur_num < thread_max_num)){
//扩容
tp->threadid = (pthread_t *)realloc(tp->threadid,
(thread_cur_num + 1) * sizeof (pthread_t)); /**< 新增线程 */
pthread_create(&(tp->threadid[current_pthread_num]),
NULL, ThreadPoolRoutine, (void*)pool);
tp->thread_cur_num++; /**< 当前池中线程总数加1 */
}
我们这里的扩容有用到realloc函数。在之前malloc出来的thread_id的空间大小上进行扩容,新的地址空间作为pthread_create()函数的第一个参数。
3.缩容:在线程从任务队列取出任务执行之后进行判断:
if ((tp->thread_cur_num - tp->thread_cur_tasknum)
> tp->thread_free_num)
{
//缩容
thread_cur_num--;
break;
}
因为每个线程执行前的一件事我们都进行了pthread_detach(),所以直接break,线程就会自动回收。
2.动态线程池的实现代码
#ifndef __THREAD_POOL_HPP__
#define __THREAD_POLL_HPP__
/*线程池
*1.线程池中有五个线程
*2.利用条件变量
*3.在队列总添加任务
* queue<Task> task_queue
*4.加锁
* pthread_mutex_t lock
*5.唤醒
* pthread_cond_t cond
*6.任务类
*
*/
#include<iostream>
#include<pthread.h>
#include<queue>
#include<sys/time.h>
#include<unistd.h>
#define NUM 5
#include"Log.hpp"
using namespace std;
typedef int(*handler_t) (int);
//任务结构
class Task
{
private:
int sock_;
handler_t handler_;
public:
Task()
{
sock_ = -1;
handler_ = NULL;
}
void SetTask(int sock, handler_t handler)
{
sock_ = sock;
handler_ = handler;
}
void Run()
{
handler_(sock_);
}
~Task()
{}
};
//线程池
class ThreadPool
{
private:
//int thread_total_num;
int thread_free_num; //最大休眠线程数
queue<Task> task_queue;
pthread_t *thread_id;
int thread_max_num; //线程池容纳最大线程数
int thread_cur_num; //当前线程池存放的线程数
int thread_cur_task_num //当前工作的线程数
pthread_mutex_t lock;
pthread_cond_t cond;
bool isquit;
private:
void LockQueue()
{
pthread_mutex_lock(&lock);
}
void UnLockQueue()
{
pthread_mutex_unlock(&lock);
}
void GetTask(Task & t)
{
t = task_queue.front();
task_queue.pop();
}
bool IsEmpty()
{
if (task_queue.size() == 0)
return true;
return false;
}
void ThreadWait()
{
//如果线程池退出了则线程退出
if (isquit)
{
//退出前解锁
UnLockQueue();
thread_total_num--;
pthread_exit((void*)0);
}
pthread_cond_wait(&cond, &lock);
thread_idle_num++;
}
void WeakUpThread()
{
pthread_cond_signal(&cond);
thread_idle_num--;
}
void WeakUpAllThread()
{
pthread_cond_broadcast(&cond);
}
//如果不是static会有this指针
static void* Thread_Routine(void* arg)
{
//分离线程
ThreadPool* tp = (ThreadPool*)arg;
pthread_detach(pthread_self());
while (1)
{
tp->LockQueue();
while (tp->IsEmpty())
{
//等待
tp->ThreadWait();
}
//取任务
Task t;
tp->GetTask(t);
tp->thread_cur_task_num++;
//解锁
tp->UnLockQueue();
//处理任务
t.Run();
if ((tp->thread_cur_num - tp->thread_cur_tasknum) > tp->thread_free_num)
{
//缩容
thread_cur_num--;
break;
}
}
}
public:
ThreadPool(int n1 =20 , int n2 = 2) :thread_max_num(n1), thread_free_num(n2), thread_cur_task_num(0)
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
}
void InitThreadPool()
{
int i = 0;
//pthread_t id[NUM];
thread_id = (pthread_t *)malloc(NUM*sizeof(pthread_t));
for (i; i < NUM; i++)
{
pthread_create(&thread_id[i], NULL, Thread_Routine, this);
thread_cur_num++;
}
LOG(INFO, "create thread");
}
void PushTask(Task& t)
{
//加锁
LockQueue();
//如果是需要退出了则不能在继续添加线程
if (isquit)
{
UnLockQueue();
return;
}
if ((thread_cur_task_num == thread_cur_num) && (thread_cur_num < thread_max_num)){
//扩容
tp->threadid = (pthread_t *)realloc(tp->threadid, (current_pthread_num + 1) * sizeof (pthread_t)); /**< 新增线程 */
pthread_create(&(tp->threadid[current_pthread_num]), NULL, ThreadPoolRoutine, (void*)pool);
pool->current_pthread_num++; /**< 当前池中线程总数加1 */
}
//添加任务
task_queue.push(t);
//唤醒线程
WeakUpThread();
//解锁
UnLockQueue();
}
void StopThread()
{
//加锁
LockQueue();
//isqueue设置为true
isquit = true;
//解锁
UnLockQueue();
if (thread_idle_num > 0)
{
WeakUpAllThread();
}
}
~ThreadPool()
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
}
};
#endif
具体的实现与之前的代码其实差别不是太大,代码里边有的变量名字可能需要订正,并不影响解读。