线程池C++实现,底层支持pthread,windows平台

线程池

线程池的概念在这里就不一一赘述,本文主要实现的线程池是基于pthread库,然后开发环境的windows平台,IDE VS2015。本文主要实现的功能就是实现一个线程池,线程池的大小可以用户自定义,线程处理函数也可以用户自定义。操作简单,使用方便,目前只是初次编写,如果有问题欢迎大家提出。至于pthread在window的配置和普通的添加include lib dll文件一样。

结构图

在这里插入图片描述
整个流程大概如此,在处理事件中存放的ThreadTask*整个基类的指针,只要添加任务的时候继承于基类,并重写doTask()方法既可以完成相应的自己添加的线程函数。

线程池声明的头文件ThreadPool Class

#pragma once
#define HAVE_STRUCT_TIMESPEC
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <vector>
#include"ThreadTask.h"
#pragma comment(lib, "pthreadVC2.lib")
#define CIRCLETIME 1000
typedef long long llong;
class ThreadPool
{
public:
	//构造函数
	/*

	 */
	ThreadPool(int minThreadPool = 10, int maxThreadPool = 100, int queueSize = 100);
	//用户自己选择是否要加入管理者线程。
	/*管理者线程,自动管理线程池,当线程的繁忙数量/存在数量>0.8(默认)时开始增加线程,
	 *当小于0.3时,开始减少线程,每次增加较少的为繁忙线程的0.25或者较少存在线程的0.25
	 *这样可以使得线程池的工作量始终保持在0.4-0.6666之间,用户也可以改变默认参数
	*para: maxThreshold, 增加线程的阈值
	*para: minThreshodl, 减少线程的阈值
	*para: weight, 增加或者减少的比重
	*/
	void addAdjustThread(float maxThreshold=0.8,float minThreshodl=0.3,float weight=0.25);
	
	//朝线程池中添加任务
	void addTask(ThreadTask*);
	
	//访问线程一些资源的方法
	inline int getLiveNum() const {
		return _liveThreadNum;
	}
	inline int getBusyNum() const {
		return _busyThreadNum;
	}
	virtual ~ThreadPool();
private:
	//线程调用函数
	static void *threadpoolTask(void *threadpool);
	//管理者线程方法
	static void *adjustThread(void *threadpool);
	//判断线程是否活着
	bool isAlive(pthread_t tid);
	//释放线程池资源
	void threadPoolFree();
	//销毁线程池
	bool threadPoolDestroy();


private:
	int _minimumPoolSize;       //默认线程池的大小
	int _maximumPoolSize;   //线程池最大线程个数 
	int _liveThreadNum;     //存活的线程个数
	int _busyThreadNum;     //忙状态的线程个数
	int _waitExitThreadNum; //需要销毁的线程个数

	//锁
	pthread_mutex_t _lock;                //锁住整个class
	pthread_mutex_t _threadCounter;       //锁住用来记录忙线程的个数
	pthread_cond_t  _queueNotFull;      /* 当任务队列满时,添加任务的线程阻塞,等待此条件变量 */
	pthread_cond_t  _queueNotEmpty;     /* 任务队列里不为空时,通知等待任务的线程 */

	pthread_t *_threads;                        /* 存放线程池中每个线程的tid。数组 */
	pthread_t _adjustTid;                     /* 存管理线程tid */
	std::vector<ThreadTask*>* _taskQueue;      /* 任务队列 ,用vector模拟循环队列*/

	int _queueFront;                    /* task_queue队头下标 */
	int _queueRear;                     /* task_queue队尾下标 */
	int _queueSize;                     /* task_queue队中实际任务数 */
	int _queueMaxSize;                 /* task_queue队列可容纳任务数上限 */

	bool _shutdown;                     /* 标志位,线程池使用状态,true或false */

	float _maxThreshold;
	float _minThreshold;
	float _weight;

};


线程池定义的Cpp文件

#include "ThreadPool.h"
#include<iostream>
#include<Windows.h>

ThreadPool::ThreadPool(int minThreadPool, int maxThreadPool, int queueSize) :
	_minimumPoolSize(minThreadPool),
	_maximumPoolSize(maxThreadPool),
	_liveThreadNum(minThreadPool),
	_busyThreadNum(0),
	_waitExitThreadNum(0),
	_lock(NULL),
	_threadCounter(NULL),
	_queueNotFull(NULL),
	_queueNotEmpty(NULL),
	_threads(NULL),
	_taskQueue(NULL),
	_queueFront(0),
	_queueRear(0),
	_queueSize(0),
	_queueMaxSize(queueSize),
	_shutdown(false),
	_maxThreshold(0.0),
	_minThreshold(0.0),
	_weight(0.0)

{
	do {
		_threads = new pthread_t[_maximumPoolSize];//创建线程池
		if (nullptr == _threads) {
			std::cout << "bad_alloc" << std::endl;
			break;
		}
		//初始化锁
		if (pthread_mutex_init(&_lock, NULL) != 0
			|| pthread_mutex_init(&_threadCounter, NULL) != 0
			|| pthread_cond_init(&_queueNotFull, NULL) != 0
			|| pthread_cond_init(&_queueNotEmpty, NULL) != 0)
		{
			std::cout << "init lock or cond fail" << std::endl;
			break;
		}
		_taskQueue = new std::vector<ThreadTask*>(queueSize, nullptr);
		//启动最小的工作线程
		
		
		//using cel = ThreadPool::*p;
		for (int i = 0; i < _minimumPoolSize; ++i) {
			pthread_create(&_threads[i], NULL, &ThreadPool::threadpoolTask, this);
		}

		//启动管理者线程
		return;
	} while (0);
	threadPoolFree();
	return;
	
}

void ThreadPool::addAdjustThread(float maxThreshold, float minThreshold, float weight)
{
	_maxThreshold = maxThreshold;
	_minThreshold = minThreshold;
	_weight = weight;
	pthread_create(&this->_adjustTid, NULL, &ThreadPool::adjustThread, this);
}

void ThreadPool::threadPoolFree()
{
	if (_threads != nullptr) {
		delete[]_threads;
		pthread_mutex_lock(&(_lock));
		pthread_mutex_destroy(&(_lock));
		pthread_mutex_lock(&(_threadCounter));
		pthread_mutex_destroy(&(_threadCounter));
		pthread_cond_destroy(&(_queueNotEmpty));
		pthread_cond_destroy(&(_queueNotFull));

	}
	if (_taskQueue != nullptr) {
		delete _taskQueue;
	}
	
}

bool ThreadPool::threadPoolDestroy()
{
	if (nullptr == this) {
		return false;
	}
	_shutdown = true;
	//关闭管理者线程
	if (_adjustTid.x == 0) {
		pthread_join(_adjustTid, NULL);
	}
	for (int i = 0; i < _liveThreadNum; ++i) {
		//通知所有空闲线程
		pthread_cond_broadcast(&_queueNotEmpty);

	}
	for (int i = 0; i < _liveThreadNum; i++) {
		printf("thread %d is waiting\n", _threads[i].x);
		pthread_cancel(_threads[i]); //通知子线程结束
		pthread_join(_threads[i], NULL);
	}
	threadPoolFree();
	return true;
}

ThreadPool::~ThreadPool()
{
	threadPoolDestroy();
}
void ThreadPool::addTask(ThreadTask *task)
{
	pthread_mutex_lock(&(_lock));
	/* ==为真,队列已经满, 调wait阻塞 */
	while ((_queueSize == _queueMaxSize) && (!_shutdown)) {
		pthread_cond_wait(&(_queueNotFull), &(_lock));//阻塞
	}
	if (_shutdown) {
		pthread_mutex_unlock(&(_lock));
	}
	if ((*_taskQueue)[_queueRear] != nullptr) {
		//队列已经满了

	}
	(*_taskQueue)[_queueRear] = task;
	_queueRear = (_queueRear + 1) % _queueMaxSize;       /* 队尾指针移动, 模拟环形 */
	_queueSize++;
	/*添加完任务后,队列不为空,唤醒线程池中 等待处理任务的线程*/
	pthread_cond_signal(&(_queueNotEmpty));
	pthread_mutex_unlock(&(_lock));
}

void * ThreadPool::threadpoolTask(void * threadpool)
{
	ThreadPool* pool = (ThreadPool*)threadpool;
	ThreadTask* task;
	while (true)
	{
		
		pthread_mutex_lock(&(pool->_lock));
		/*_queueSize == 0 说明没有任务,调 wait 阻塞在条件变量上, 若有任务,跳过该while*/
		while (pool->_queueSize == 0 && (!pool->_shutdown))
		{
			printf("thread %d is waiting\n", pthread_self());
			pthread_cond_wait(&(pool->_queueNotEmpty), &(pool->_lock));

			/*清除指定数目的空闲线程,如果要结束的线程个数大于0,结束线程*/
			if (pool->_waitExitThreadNum > 0) {
				pool->_waitExitThreadNum--;

				/*如果线程池里线程个数大于最小值时可以结束当前线程*/
				if (pool->_liveThreadNum > pool->_minimumPoolSize) {
					printf("thread %d is exiting\n", pthread_self());
					pool->_liveThreadNum--;
					pthread_mutex_unlock(&(pool->_lock));
					pthread_exit(NULL);
				}
			}

		}
		/*如果指定了true,要关闭线程池里的每个线程,自行退出处理*/
		if (pool->_shutdown) {
			pthread_mutex_unlock(&(pool->_lock));
			printf("thread %d is exiting\n", pthread_self());
			pthread_exit(NULL);     /* 线程自行结束 */
		}
		task = (*pool->_taskQueue)[pool->_queueFront];
		(*pool->_taskQueue)[pool->_queueFront] = nullptr;

		pool->_queueFront = (pool->_queueFront + 1) % pool->_queueMaxSize;
		pool->_queueSize--;

		/*通知可以有新的任务添加进来*/
		pthread_cond_broadcast(&(pool->_queueNotFull));
		/*任务取出后,立即将 线程池琐 释放*/
		pthread_mutex_unlock(&(pool->_lock));

		/*执行任务*/
		printf("thread %d start working\n", pthread_self());
		pthread_mutex_lock(&(pool->_threadCounter));                            /*忙状态线程数变量琐*/
		pool->_busyThreadNum++;                                                /*忙状态线程数+1*/
		pthread_mutex_unlock(&(pool->_threadCounter));
		task->threadTask();

		/*任务结束处理*/
		printf("thread %d end working\n", pthread_self());
		pthread_mutex_lock(&(pool->_threadCounter));
		pool->_busyThreadNum--;                                       /*处理掉一个任务,忙状态数线程数-1*/
		pthread_mutex_unlock(&(pool->_threadCounter));
	}
	pthread_exit(NULL);
	return nullptr;
}

void * ThreadPool::adjustThread(void * threadpool)
{
	ThreadPool* pool = (ThreadPool*)threadpool;
	while (!pool->_shutdown)
	{
		Sleep(CIRCLETIME); //每隔5s扫描一次
		pthread_mutex_lock(&(pool->_lock));
		int queue_size = pool->_queueSize;                      /* 关注 任务数 */
		int live_thr_num = pool->_liveThreadNum;                  /* 存活 线程数 */
		pthread_mutex_unlock(&(pool->_lock));

		pthread_mutex_lock(&(pool->_threadCounter));
		int busy_thr_num = pool->_busyThreadNum;                  /* 忙着的线程数 */
		pthread_mutex_unlock(&(pool->_threadCounter));

		if (busy_thr_num / (double)live_thr_num > pool->_maxThreshold) {
			pthread_mutex_lock(&(pool->_lock));
			int addNum = pool->_weight*busy_thr_num;
			for (int i = 0; i < pool->_maximumPoolSize && addNum&&pool->_liveThreadNum<pool->_maximumPoolSize; ++i) {
				//增加线程
				//pool->_threads[i].p == 0 ||
				if (pool->_threads[i].x != 0|| !pool->isAlive(pool->_threads[i])) {
					pthread_create(&(pool->_threads[i]), NULL, pool->threadpoolTask, (void *)pool);
					addNum--;
					pool->_liveThreadNum++;
				}

			}

			pthread_mutex_unlock(&(pool->_lock));
		}
		if (busy_thr_num / (double)live_thr_num < pool->_minThreshold) {
			//减少存在的线程
			pthread_mutex_lock(&(pool->_lock));
			int deleteNum = pool->_weight*live_thr_num;
			pool->_waitExitThreadNum = deleteNum;      /* 要销毁的线程数 设置为10 */
			pthread_mutex_unlock(&(pool->_lock));
			for (int i = 0; i < deleteNum; i++) {
				/* 通知处在空闲状态的线程, 他们会自行终止*/
				pthread_cond_signal(&(pool->_queueNotEmpty));
			}
		}
	}
	return nullptr;
}

bool ThreadPool::isAlive(pthread_t tid)
{

	int kill_rc = pthread_kill(tid, 0);     //发0号信号,测试线程是否存活
	if (kill_rc == ESRCH) {
		return false;
	}

	return true;
}

ThreadTask声明的头文件

#pragma once
#define HAVE_STRUCT_TIMESPEC
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <vector>
#pragma comment(lib, "pthreadVC2.lib")
class ThreadTask
{
public:
	ThreadTask();
	//加入这个函数的目的是,取消线程的时候,线程池会发出一个CANCEL的信号
	//我们需要有接受这个信号的方法,从而结束线程,以防止子线程陷入死循环
	void threadTask();
	virtual void doTask() = 0;
	virtual ~ThreadTask();
};


ThreadTask定义的Cpp

#include "ThreadTask.h"



ThreadTask::ThreadTask()
{
}

void ThreadTask::threadTask()
{
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
	this->doTask();
}


ThreadTask::~ThreadTask()
{
}

测试的主函数

//main.cpp
#define HAVE_STRUCT_TIMESPEC
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include<Windows.h>
#include<iostream>
#include"ThreadPool.h"
#include"ThreadTask.h"
#pragma comment(lib, "pthreadVC2.lib")


class TaskA :public ThreadTask{
public:
	TaskA(int num=0):num(num){}
	virtual void doTask() {
		std::cout << "我是线程A num=:" << num << std::endl;
		return;
	}
private:
	int num;
};

class TaskB :public ThreadTask {
public:
	TaskB(int num = 0) :num(num) {}
	virtual void doTask() {
		std::cout << "我是线程B num=:" << num << std::endl;
		while (true)
		{
			
		}
		return;
	}
private:
	int num;
};
int main()
{
	ThreadPool threadPool(5,40);//不建议太大
	std::vector<ThreadTask *>temp; //防止内存泄漏,这里没起作用,以防万一,因为下面的a被使用后就没了。
	threadPool.addAdjustThread();
	for (int i = 0; i < 110; ++i) {
		ThreadTask *a = new TaskB(i);
		//ThreadTask *a = new TaskA(i);
		threadPool.addTask(a);
		temp.push_back(a);
	}
	std::cout << threadPool.getLiveNum() << std::endl;
	std::cout << threadPool.getBusyNum() << std::endl;
	Sleep(1000);
	std::cout << threadPool.getLiveNum() << std::endl;
	std::cout << threadPool.getBusyNum() << std::endl;
	Sleep(1000);
	std::cout << threadPool.getLiveNum() << std::endl;
	std::cout << threadPool.getBusyNum() << std::endl;
	system("pause");
	return 0;
}

小结

本文主要通过使用pthread库实现了线程池,当然C++11支持thread创建多线程的方式。因为是学习阶段,这只是初步的尝试,后期如果有什么建议大家可以指出,如果建议较多可以慢慢完善。如果有需求,下一步计划完全使用C++11及以上的版本实现线程池,然后不断的完善。如果能做成一个好用的模板当然更好,有什么意见大家可以多多提。特别是bug。我自己在测试的时候发现线程到50-100的时候CPU的使用率直线上升。可能有bug希望大佬能提出来。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值