C++高并发服务器-线程池

一、线程池的概念

        线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务。

二、为什么要用线程池

直接创建销毁线程的缺点

    我们使用线程的目的本是出于效率考虑,可以为了创建这些线程却消耗了额外的时间,资源,对于线程的销毁同样需要系统资源。

    cpu资源有限,上述代码创建线程过多,造成有的任务不能即时完成,响应时间过长。

    线程无法管理,无节制地创建线程对于有限的资源来说似乎成了“得不偿失”的一种作用。

线程池的好处

    降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

    提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

    提高线程的可管理性。

三、线程池的组件

 关键部分讲解:

        1.管理员线程:管理员线程在线程池存在时就一直检测线程池(每秒检测一次),在检测期间做如下任务:

  • 加锁获取线程池的执行任务线程数量和任务数
  • 添加线程策略/算法(当前任务个数>存活的线程数 && 存活的线程数<最大线程个数),线程池加锁,然后向线程池中加工作线程
  • 销毁多余的线程(忙线程*2 < 存活的线程数目 && 存活的线程数 > 最小线程数量2.

         2.工作线程:在线程池创建时被创建,用一个线程数组保存,没有任务时阻塞,有任务时取出任务并执行。

    访问任务队列(共享资源)时加锁
    判断任务队列是否为空,如果为空则工作线程阻塞(等待条件变量),解除阻塞(收到条件变量,但有可能是要求销毁线程)先判断是否要销毁线程(如果待退出的线程数大于0则需要退出线程,另外如果线程池关闭标志为真也需要退出),然后从任务队列中取出一个任务并执行。循环此过程。
3.线程池回收

  • 在线程池关闭或管理员线程销毁多于线程时执行
  • 调用threadExit(pthread_self())

4.线程池创建

  • 实例化任务队列,初始化各成员变量
  • 根据线程池最大数量给线程数组分配内存
  • 初始化条件变量和互斥锁
  • 创建工作线程和管理员线程

5.线程池析构

  • 将线程池关闭标志置为真,先销毁管理员线程
  • 再唤醒所有工作线程让他们自己结束。
  • 销毁条件变量、互斥锁

代码实现(ThreadPool类):

#pragma once

#include"TaskQueue.h"
class ThreadPool{
public:
	ThreadPool(int minNum,int maxNum);
	~ThreadPool();
	void addTask(Task &task);
	int getBusyNum();
	int getAliveNum();
private:
	static void* worker(void* arg);
	static void* manager(void* arg);
	void ThreadExit();
	TaskQueue* m_tq;
	pthread_mutex_t m_mutex;
	pthread_cond_t m_not_empty;
	pthread_t* m_pworkerThreadId;
	pthread_t m_managerThreadId;
	int m_minNum;
	int m_maxNum;
	int m_busyNum;
	int m_aliveNum;
	int m_exitNum;
	bool m_shutdown=false;
};
#include"ThreadPool.h"

#include<iostream>
#include<string.h>
#include<unistd.h>
#include<string>

using namespace std;

ThreadPool::ThreadPool(int minNum,int maxNum) {
	m_tq=new TaskQueue;
	do{
		m_minNum = minNum;
		m_maxNum = maxNum;
		m_busyNum=0;
		m_aliveNum=minNum;
		m_exitNum=0;

		m_pworkerThreadId=new pthread_t[maxNum];
		if(m_pworkerThreadId==nullptr){
			cout<<"malloc thread_t[] failed..."<<endl;
			break;
		}
		memset(m_pworkerThreadId,0,sizeof(pthread_t)*maxNum);
		if(pthread_mutex_init(&m_mutex,NULL)!=0||pthread_cond_init(&m_not_empty,NULL)!=0){
			cout<<"init mutex or condition failed"<<endl;
			break;

		}

		//create threads
		for(int i=0;i<minNum;i++){
			cout<<"create thread..."<<endl;
			pthread_create(&m_pworkerThreadId[i],NULL,worker,this);
		}
		pthread_create(&m_managerThreadId,NULL,manager,this);

	}while(0);

}

ThreadPool::~ThreadPool(){
	m_shutdown=1;

	pthread_join(m_managerThreadId,NULL);
	cout<<"manager thread is destroyed"<<endl;

	for(int i=0;i<m_aliveNum;i++){
		pthread_cond_signal(&m_not_empty);
	}
	cout<<"worker thread is destroyed"<<endl;

	if(m_tq)delete m_tq;
	if(m_pworkerThreadId)delete m_pworkerThreadId;;
	pthread_mutex_destroy(&m_mutex);
	pthread_cond_destroy(&m_not_empty);
	cout<<"thread pool destroyed"<<endl;
}

void ThreadPool::addTask(Task &task){
	if(m_shutdown){
		return;
	}
	cout<<"Add task to pool"<<endl;
	m_tq->addTask(task);
	pthread_cond_signal(&m_not_empty);
}
int ThreadPool::getAliveNum(){
	int threadNum = 0;
	pthread_mutex_lock(&m_mutex);
	threadNum=m_aliveNum;
	pthread_mutex_unlock(&m_mutex);
	return threadNum;
}

int ThreadPool::getBusyNum(){
	int busyNum =0;
	pthread_mutex_lock(&m_mutex);
	busyNum=m_busyNum;
	pthread_mutex_unlock(&m_mutex);
	return busyNum;
}
	
void* ThreadPool::worker(void* arg){
	ThreadPool* pool=static_cast<ThreadPool*>(arg);
	while(true){
		pthread_mutex_lock(&pool->m_mutex);

		while(pool->m_tq->size()==0&&!pool->m_shutdown){
			cout<<"worker thread"<<to_string(pthread_self())<<"waiting..."<<endl;
			pthread_cond_wait(&pool->m_not_empty,&pool->m_mutex);
			if(pool->m_exitNum>0){
				//there are some thread need to be destroied
				pool->m_aliveNum--;
				pthread_mutex_unlock(&pool->m_mutex);
				pool->ThreadExit();
			}
		}
		if(pool->m_shutdown){
			pthread_mutex_unlock(&pool->m_mutex);
			pool->ThreadExit();
		}
		Task task=pool->m_tq->takeTask();
		pool->m_busyNum++;
		pthread_mutex_unlock(&pool->m_mutex);
		cout<<"worker thread "<<to_string(pthread_self())<<"start working..."<<endl;
		task.function(task.arg);
		cout<<"worker thread"<<to_string(pthread_self())<<"end working..."<<endl;
		pthread_mutex_lock(&pool->m_mutex);
		pool->m_busyNum--;
		pthread_mutex_unlock(&pool->m_mutex);		
	}
	return nullptr;
}

void* ThreadPool::manager(void* arg){
	ThreadPool *pool=static_cast<ThreadPool*>(arg);
	while(!pool->m_shutdown){
		sleep(1);
		pthread_mutex_lock(&pool->m_mutex);
		int queueSize=pool->m_tq->size();
		int liveNum=pool->m_aliveNum;
		int busyNum=pool->m_busyNum;
		pthread_mutex_unlock(&pool->m_mutex);

		const int NUMBER=2;//add 2 worker thread at once
		if(queueSize>liveNum&&liveNum<pool->m_maxNum){
			pthread_mutex_lock(&pool->m_mutex);
			int num=0;
			for(int i=0;i<pool->m_maxNum&&num<NUMBER;++i){
				if(pool->m_pworkerThreadId[i]==0){
					pthread_create(&pool->m_pworkerThreadId[i],NULL,worker,pool);
					num++;
					pool->m_aliveNum++;

				}
			}
			pthread_mutex_unlock(&pool->m_mutex);

		}
		//destroy rest of threads
		if(busyNum*2<liveNum&&liveNum>pool->m_minNum){
			pthread_mutex_lock(&pool->m_mutex);
			pool->m_exitNum=NUMBER;
			pthread_mutex_unlock(&pool->m_mutex);
			for(int i=0;i<NUMBER;i++){
				pthread_cond_signal(&pool->m_not_empty);
			}
		}

	}
	return nullptr;
}

void ThreadPool::ThreadExit(){
	pthread_t tid=pthread_self();
	for(int i=0;i<m_maxNum;i++){
		if(m_pworkerThreadId[i]==tid){
			cout<<"ThreadExit() :thread "<<to_string(pthread_self())<<"exiting..."<<endl;
			m_pworkerThreadId[i]=0;
			break;
		}
	}
	pthread_exit(NULL);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值