linux c++ 实现可根据当前任务数动态调整线程数量的线程池

一、threadpool.h

/*

主线程往工作队列中插入任务
工作线程通过竞争来取得任务并且执行
必须保证所有客户的请求都是无状态的
因为同一个连接上的不同请求可能会由不同线程处理

*/
#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <list>
#include <cstdio>
#include <exception>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>

#define DEFAULT_TIME 10                 /*10s检测一次*/
#define MIN_WAIT_TASK_NUM 10            /*如果queue_size > MIN_WAIT_TASK_NUM 添加新的线程到线程池*/ 
#define DEFAULT_THREAD_VARY 10          /*每次创建和销毁线程的个数*/

/*线程池类 将其定义为模板类是为了代码复用 模板参数T是任务类*/

template<typename T>
class threadpool
{
public:
	/*
		参数 	thread_number是线程池中线程的数量
				max_requests 请求队列中最多允许的等待处理的请求数量
	*/
	threadpool(int _min_thread_number =2 ,int _max_thread_number = 100, int _max_requests = 10000);
	~threadpool();

	/*往请求队列中添加任务*/
	bool append(T *request);

private:
	/*工作线程运行的函数,它不断从工作队列中取出任务并且执行*/
	static void* worker(void *arg);
	void run();
	/*管理线程函数*/
	static void* manager(void *arg);
	void adjust_thread();
	

private:

	pthread_t *threads;				/*描述线程池的数组,其大小为m_thread_number*/
	std::list<T*> work_queue;		/*请求队列*/
	bool stop;						/*是否需要结束线程池*/
	int max_requests;

	/*实现可以变长线程池新增部分*/

	pthread_t adjust_tid;           /* 存管理线程tid */
	int min_thread_number;			/* 线程池最小线程数 */
	int max_thread_number;			/* 线程池最大线程数 */
	int live_thread_number;			/* 当前存活线程个数 */
	int busy_thread_number;			/* 忙状态线程个数 */
	int wait_exit_thread_number;	/* 要销毁的线程个数 */


	pthread_mutex_t lock;               /* 用于锁住本结构体 */
	pthread_mutex_t thread_counter;     /* 记录忙状态线程个数de琐 -- busy_thr_num */
	pthread_cond_t queue_not_full;      /* 当任务队列满时,添加任务的线程阻塞,等待此条件变量 */
	pthread_cond_t queue_not_empty;     /* 任务队列里不为空时,通知等待任务的线程 */
};

template<typename T>
threadpool<T>::threadpool(int _min_thread_number,int _max_thread_number,int _max_requests)											
{
	if (_min_thread_number <= 0 || _max_thread_number <=0||_max_requests <= 0 || _min_thread_number >= _max_thread_number) //非法值警告
	{				
		printf("ERROR: Illegal value!!\n");
		throw std::exception();
	}
	min_thread_number = _min_thread_number;
	max_thread_number = _max_thread_number;
	live_thread_number = _min_thread_number;
	busy_thread_number = 0;
	wait_exit_thread_number = 0;
	max_requests = _max_requests;
	stop = false;

	/* 初始化互斥琐、条件变量 */
	if (pthread_mutex_init(&lock, NULL) != 0
		|| pthread_mutex_init(&thread_counter, NULL) != 0
		|| pthread_cond_init(&queue_not_empty, NULL) != 0
		|| pthread_cond_init(&queue_not_full, NULL) != 0)
	{
		printf("init the lock or cond fail");
		throw std::exception();
	}

	//按照最大线程数目 动态分配一个描述线程池的数组
	threads = new pthread_t[max_thread_number];				
	if (threads==NULL) 
	{
		printf("ERROR: Fail to create theads[]!!\n ");
		throw std::exception();
	}

	//创建初始线程
	for (int i = 0; i < min_thread_number; i++){
		printf("create the %dth threads\n", i);
		if (pthread_create(threads + i, NULL, worker, this) != 0) {  //使用this指针 然后在worker函数中获取该指针并调用动态方法run 

			printf("ERROR: Fail to create pthreads !!\n");
			delete[] threads;
			throw std::exception();
		}
	}
	//创建管理者线程
	printf("create the adjust_tid threads\n");

	if (pthread_create(&adjust_tid, NULL, manager, this) != 0) {  

		printf("ERROR: Fail to create adjust_tid !!\n");
		throw std::exception();
	}
	
}


template<typename T>
threadpool<T>::~threadpool()
{
	/*先销毁管理线程*/
	pthread_join(adjust_tid, NULL);

	/*回收其他线程*/
	for (int i = 0; i < live_thread_number; i++) {
		pthread_join(threads + i, NULL);
	}
	delete[] threads;

	/*销毁锁*/
	pthread_mutex_destroy(&(lock));
	pthread_mutex_destroy(&(thread_counter));
	pthread_cond_destroy(&(queue_not_empty));
	pthread_cond_destroy(&(queue_not_full));
	stop = true;
}
template<typename T>
void* threadpool<T>::worker(void *arg) {

	threadpool* pool = (threadpool*)arg;
	pool->run();
	return pool;
}

template<typename T>
bool threadpool<T>::append(T *request) {
	
	pthread_mutex_lock(&lock);									//上锁 进入临界区
	while (work_queue.size() == max_requests and !stop) {		//队列已经满了
		pthread_cond_wait(&queue_not_full, &lock);				//等待队列非满
	}
	if (stop) {													//如果线程池已经停止运行了 解锁
		pthread_mutex_unlock(&lock);
		return false;
	}
	work_queue.push_back(request);							    //把新的请求放入队列中
	pthread_cond_signal(&queue_not_empty);						/*添加完任务后,队列不为空,唤醒线程池中 等待处理任务的线程*/
	pthread_mutex_unlock(&lock);
	return true;

}
template<typename T>
void threadpool<T>::run() {
	while (true) {
		pthread_mutex_lock(&lock);									//上锁 进入临界区
		while (work_queue.size() == 0 and !stop) {					//队列为空
			pthread_cond_wait(&queue_not_empty, &lock);				//等待队列非空
			
			/*清除指定数目的空闲线程,如果要结束的线程个数大于0,结束线程*/
			if (wait_exit_thread_number > 0) {
				wait_exit_thread_number--;

				/*如果线程池里线程个数大于最小值时可以结束当前线程*/
				if (live_thread_number > min_thread_number) {
					
					live_thread_number--;
					pthread_mutex_unlock(&lock);
					pthread_exit(NULL);
				}
			}
		}
		/*如果指定了true,要关闭线程池里的每个线程,自行退出处理*/
		if (stop) {
			pthread_mutex_unlock(&lock);
			pthread_exit(NULL);     /* 线程自行结束 */
		}

		/*从任务队列里获取任务, 是一个出队操作*/
		T* request = work_queue.front();				//获取请求队列队首请求				
		work_queue.pop_front();
		
		/*通知可以有新的任务添加进来*/
		pthread_cond_broadcast(&queue_not_full);
		
		/*任务取出后,立即解 线程池 锁*/
		pthread_mutex_unlock(&lock);

		/*开始执行任务*/
		pthread_mutex_lock(&thread_counter);			/*忙状态线程数变量琐*/
		busy_thread_number++;							/*忙状态线程数+1*/
		pthread_mutex_unlock(&thread_counter);

		/*处理任务*/
		request->process();

		/*任务结束*/
		pthread_mutex_lock(&thread_counter);			/*忙状态线程数变量琐*/
		busy_thread_number--;							/*忙状态线程数-1*/
		pthread_mutex_unlock(&thread_counter);
	}
	pthread_exit(NULL);
}
template<typename T>
 void * threadpool<T>::manager(void *arg)
{
	 threadpool* pool = (threadpool*)arg;
	 pool->adjust_thread();
	 return pool;
}

template<typename T>
void threadpool<T>::adjust_thread() {

	while(!stop)
	{
		sleep(DEFAULT_TIME);								/*定时 对线程池管理*/
		pthread_mutex_lock(&lock);							//上锁 进入临界区
		int work_queue_size = work_queue.size();			/* 关注 任务数 */
		int live_thr_num = live_thread_number;				/* 存活 线程数 */
		pthread_mutex_unlock(&lock);						//解锁 退出临界区

		pthread_mutex_lock(&lock);							//上锁 进入临界区
		int busy_thr_num = busy_thread_number;				/* 忙着的线程数 */
		pthread_mutex_unlock(&lock);						//解锁 退出临界区

		/* 创建新线程 算法: 当前任务数大于最小任务数, 且存活的线程数少于允许最大线程个数时 如:30>=10 && 40<100 */
		if (work_queue_size >= MIN_WAIT_TASK_NUM && live_thr_num < max_thread_number) {
			pthread_mutex_lock(&lock);						//上锁 进入临界区
			int add = 0;

			/*一次增加 DEFAULT_THREAD 个线程*/
			for (int i = 0; i < max_thread_number && add < DEFAULT_THREAD_VARY
				&& live_thread_number < max_thread_number; i++) {
				/*
					pthread_kill(tid, 0) 给这个tid发送一个0  
					查看这个线程是否存活
					没有活着就返回ESRCH
				*/
				if (threads[i] == 0 || (pthread_kill(threads[i], 0)== ESRCH)) {
					pthread_create(threads+i, NULL, worker, this);
					add++;
					live_thread_number++;
				}
			}
			pthread_mutex_unlock(&lock);					//解锁 退出临界区
		}
		/* 销毁多余的空闲线程 算法:忙线程X2 小于 存活的线程数 且 存活的线程数 大于 最小线程数时*/
		if ((busy_thr_num * 2) < live_thr_num  &&  live_thr_num > min_thread_number) {
			pthread_mutex_lock(&lock);						//上锁 进入临界区
			wait_exit_thread_number = DEFAULT_THREAD_VARY;	/* 要销毁的线程数 设置为10 */
			pthread_mutex_unlock(&lock);					//解锁 退出临界区
			for (int i = 0; i < DEFAULT_THREAD_VARY; i++) {
				/* 通知处在空闲状态的线程, 他们会自行终止*/
				pthread_cond_signal(&queue_not_empty);
			}
		}
	}
}

#endif

二、main.cpp

#include <cstdio>
#include <iostream>
#include "threadpool.h"
#include <unistd.h>

using namespace std;
class User
{
public:
	void process() {
		pthread_t tid = pthread_self();
		printf("I am Child thread:%u\n",tid);
	}
};

int main()
{
	threadpool<User>* pool = NULL;
	try
	{
		pool = new threadpool<User>;
	}
	catch (...)
	{
		return 1;
	}
	User* user = new User[1000];
	pthread_t tid = pthread_self();
	while (true) {
		for (int i = 0; i < 1000; i++)
		{
			printf("I am Parent thread:%u\n", tid);
			pool->append(user + i);
		}
	}
	return 0;
}

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值