(c++)手撕线程池ThreadPool

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言:为什么需要线程池?

提示:这里可以添加本文要记录的大概内容:

当我们有某项工作需要调用线程执行时,需要创建线程,工作完成后销毁线程,然而创建和销毁开销较大,这时引入了线程池。
当有任务进来时存放在线程池的任务队列中存储。
线程池中维护了一定的数量的活着的工作者线程,没有任务时保持阻塞状态,有任务时去任务然后执行。
管理者线程负责管理线程池中线程数量,根据任务数量判断,线程太多了需要销毁一些,太少了需要创建。

一、线程池是什么

线程池的本质就是一个类/一种数据结构,这个类能够实现某些指定的功能
1.能够存放任务队列
2.工作线程(n个,负责从任务队列中取任务并处理(相当于消费者),
3.管理者线程(1个,管理工作者线程
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

二、源码

1.threadpool.cpp

代码如下(示例):

#include "threadpool.h"
#include <iostream>
#include <string.h>
#include<pthread.h>

/*
* 线程池中某些函数已经使用mutexpool加锁,保证是互斥操作,调用者些函数时应保证mutex是打开的状态,否则会发生
* 死锁
*/

Threadpool::Threadpool(int& min, int& max)
{
	//互斥锁条件变量
	if ((pthread_mutex_init(&mutexPool, NULL)) != 0 || (pthread_cond_init(&notEmpty, NULL)) != 0)
	{
		std::cout<<"mutex or cond init failed\n"<< std::endl; return;
	}
	minNum = min;
	maxNum = max;
	busyNum = 0;
	exitNum = 0;
	liveNum = min;

	//初始化任务队列
	// 
	taskq = new TaskQueue;
//	std::cout << "taskq->taskNumber()  :"<< taskq->taskNumber()  << "\n" << std::endl;

	workIDs.assign(maxNum, 0);

//	std::cout << "workIDs.size() :" << workIDs.size() << "\n" << std::endl;
	//创建线程
	//manager函数,管理者线程的工作
	pthread_create(&managerID, NULL, manager, this);
	std::cout << "createmanagerID:"<< std::to_string(managerID )<< "\n" << std::endl;

	//此处manager函数需要在threadpool类中设置为静态成员(非静态函数在类对象被创建时才有地址
	//或者将函数定义在类外,用友元,(破坏了函数封装
	//传入this到manager函数中,也就是创建pool对象后将对象传入到函数中

	//pthread_t workid=0;
	//std::cout << "workid:::" <<workid << "\n" << std::endl;

	for (int ii = 0; ii < minNum; ii++) {
		//work()函数,工作者线程对应的工作:不断从任务队列中取任务执行
		pthread_create(&workIDs.at(ii), NULL, worker, this);
		std::cout << "create son id:::::" << std::to_string(workIDs.at(ii) )<< "\n" << std::endl;

	}
}

Threadpool::~Threadpool()
{
	shutdown = true;
	//回收管理者线程
	pthread_join(managerID, NULL);
	//唤醒阻塞进程自杀
	for (int i = 0; i < liveNum; i++) {
		pthread_cond_signal(&notEmpty);
	}
	//释放堆内存
	if (taskq) {
		delete taskq;
	}
	pthread_mutex_destroy(&mutexPool);
	pthread_cond_destroy(&notEmpty);
}

int Threadpool::addTask(Task task)
{
	//
//	std::cout << "in addTask taskq:" << taskq->taskNumber()  << "\n" << std::endl;

	if (shutdown) {
		std::cout << "shutdown pool" << "\n" << std::endl;

		return -2;

	}
	//添加任务后唤醒线程,生产者
	//
	if (!taskq->addTask(task)) {
		//printf("taskq.addtaskq,failed \n");
		std::cout << "taskq.addtaskq, failed " << "\n" << std::endl;

		return -1;
	}
//	std::cout << "out addTask taskq:www" << taskq->taskNumber() << "\n" << std::endl;
	pthread_cond_signal(&notEmpty);
	return 0;
}

int Threadpool::getBusyNum()
{
	int busyNum=0;
	pthread_mutex_lock(&mutexPool);
	busyNum = this->busyNum;
	pthread_mutex_unlock(&mutexPool);
	return busyNum;

}

int Threadpool::getAliveNum()
{
	int liveNum = 0;
	pthread_mutex_lock(&mutexPool);
	liveNum = this->liveNum;
	pthread_mutex_unlock(&mutexPool);
	return liveNum;
}

void* Threadpool::worker(void* arg)	//消费者
{
	//传入的是pool对象,强制类型转换
	Threadpool* pool = static_cast<Threadpool *>(arg);
//	std::cout << "in worker shutdown_v " << pool->shutdown << "\n" << std::endl;

	while (true) {
		usleep(100);
		//只有一个线程会进入线程池
		pthread_mutex_lock(&(pool->mutexPool));
		//任务队列为空!!!,阻塞工作线程
		while (pool->taskq->taskNumber() == 0 && !pool->shutdown) {
			//
			pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);

			//阻塞之后判断是否销毁线程(由管理者线程赋值exitnum
			if (pool->exitNum > 0) {
				pool->exitNum--;
				if (pool->liveNum > pool->minNum) {
					pool->liveNum--;
					pthread_mutex_unlock(&(pool->mutexPool));
					std::cout << "thread exiting. " << pthread_self() << "\n" << std::endl;
					pool->threadExit();
				}
			}
		}
		//如果线程池关闭
		if (pool->shutdown) {
			pthread_mutex_unlock(&(pool->mutexPool));
			pool->threadExit();
		}
		//取任务
		std::cout << "begin take task,tasksize:  " << pool->taskq->taskNumber() << "\n" << std::endl;
		//忙线程+1
		Task task = pool->taskq->takeTask();
		pool->busyNum++;
		std::cout << "end take task  ,tasksize:" << pool->taskq->taskNumber()<< "\n" << std::endl;

		pthread_mutex_unlock(&(pool->mutexPool));

		//work
		std::cout << "thread" << std::to_string(pthread_self()) << "start working..." << std::endl;
		task.function(task.arg);
		//delete(task.arg);
		task.arg = nullptr;
		std::cout << "thread" << std::to_string(pthread_self()) << "end working..." << std::endl;
		//忙线程-1
		pthread_mutex_lock(&(pool->mutexPool));
		pool->busyNum--;
		pthread_mutex_unlock(&(pool->mutexPool));
	}
	return nullptr;
}

void* Threadpool::manager(void* arg)
{
	std::cout << "in manager:" << "\n" << std::endl;

	Threadpool* pool = static_cast<Threadpool*>(arg);
	//std::cout << "in manager:"  << "\n" << std::endl;
///	std::cout << "shutdown:" << pool->shutdown << "\n" << std::endl;
	int liveNum;
	int busyNum;
	int queuesize;
	while (!pool->shutdown) {
		//每隔3s检测一次
		sleep(5);
		//取出任务池中任务的数量和当前线程的数量取出busy线程数
		pthread_mutex_lock(&(pool->mutexPool));
		//std::cout << "shutdown:" << pool->shutdown << "\n" << std::endl;

		queuesize = pool->taskq->taskNumber();
		pthread_mutex_unlock(&(pool->mutexPool));
		//std::cout << "queuesize:" << queuesize << "\n" << std::endl;
		//std::cout << "\nasdasdasdasd" << "\n" << std::endl;

		liveNum = pool->getAliveNum();
		busyNum = pool->getBusyNum();

		//std::cout << "liveNum:" << liveNum <<"liveNum" << "\n" << std::endl;
		//std::cout << "busyNum:" << busyNum << "liveNum" << "\n" << std::endl;

		//添加线程

		//任务个数》存活线程数&&存活数《最大线程数
		if (queuesize > liveNum && liveNum < pool->maxNum) {
			pthread_mutex_lock(&(pool->mutexPool));

			int count = 0;
			//批量添加线程NUMBER
			for (int i = 0; i < pool->maxNum && count < pool->NUMBER && pool->liveNum < pool->maxNum; ++i) {
				if (pool->workIDs.at(i) == 0) {
					pthread_create(&pool->workIDs.at(i), NULL, worker, pool);
					std::cout << "pthread_create:" << pool->workIDs.at(i) << "\n" << std::endl;

					count++;
					pool->liveNum++;
				}
			}
			pthread_mutex_unlock(&(pool->mutexPool));
		}
		//销毁线程
		// 设置信号exitnum,让工作者线程自杀
		//busy*2<live && live>min
		if (busyNum * 2 < liveNum && liveNum > pool->minNum) {

			std::cout << "in manage_exit_thread:" << busyNum << "liveNum" << "\n" << std::endl;
			pthread_mutex_lock(&(pool->mutexPool));
			pool->exitNum = NUMBER;
			pthread_mutex_unlock(&(pool->mutexPool));
			//让工作线程自杀
			for (int i = 0; i < NUMBER; ++i) {
				pthread_cond_signal(&pool->notEmpty);
			}
		}

	}
	return nullptr;
}

void Threadpool::threadExit()
{
	pthread_t tid = pthread_self();
	for (int i = 0; i < maxNum; i++) {
		if (workIDs.at(i) == tid) {
			workIDs.at(i) = 0;
			std::cout << "threadexit() called" << std::to_string(tid) << "exiting...\n" << std::endl;
				break;
		}
	}
	pthread_exit(&tid);//退出当前线程
}


TaskQueue::TaskQueue()
{
	pthread_mutex_init(&mutexQ, NULL);
}

TaskQueue::~TaskQueue()
{
	pthread_mutex_destroy(&mutexQ);
}

bool TaskQueue::addTask(Task task)
{
	pthread_mutex_lock(&mutexQ);
	TaskQ.push(task);
	
	if (TaskQ.empty()) {
		pthread_mutex_unlock(&mutexQ);
		return false;
	}
	pthread_mutex_unlock(&mutexQ);
	return true;
}

bool TaskQueue::addTask(callback f, void* a) {
	//Task t{ f,a };
	Task t(f, a);
	pthread_mutex_lock(&mutexQ);
	TaskQ.push(t);
	if (TaskQ.empty()) {
		pthread_mutex_unlock(&mutexQ);
		return false;
	}
	pthread_mutex_unlock(&mutexQ);
	return true;

}

Task TaskQueue::takeTask()
{
	Task t;
	pthread_mutex_lock(&mutexQ);
	if (TaskQ.empty()) {
		pthread_mutex_unlock(&mutexQ);
		
		return t;
	}
	t = TaskQ.front();
	TaskQ.pop();
	pthread_mutex_unlock(&mutexQ);
	return t;
}

2.threadpool.h

代码如下(示例):

#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <unistd.h>

using callback = void (*)(void* arg);
//任务
struct Task {
	callback function;
	void* arg;
	Task() {
		this->arg = nullptr;
		function = nullptr;
	}
	Task(callback f, void* arg) {
		this->arg = arg;
		function = f;
//		std::cout << "Task:task-arg:" << (this->arg) << "\n" << std::endl;
	}
};
//任务队列
class TaskQueue {
private:
	std::queue<Task> TaskQ;

public:
	pthread_mutex_t mutexQ;
	TaskQueue();
	~TaskQueue();
	//内部已实现加锁
	bool addTask(Task task);
	//内部已实现加锁
	bool addTask(callback f, void* a);
	//内部已实现加锁
	Task takeTask();
	//inline内联函数,在类
	inline int taskNumber() {

		if (TaskQ.empty()) {
//			std::cout << "\n  TaskQ.size empty:\n" << std::endl;
			return 0;
		}
		else
			return TaskQ.size();
	}
};

//线程池
/*
*
static 函数/成员属于类而不是对象,一个类创建100个对象时,
共享static修饰的成员或变量,其他成员在每个对象都维护了一个新的。

*/
class Threadpool {
private:
	TaskQueue* taskq;		//任务队列
	pthread_t managerID;	//管理者线程id		,在创建线程时被初始化
	std::vector<pthread_t> workIDs;		//工作者线程	,创建线程池时初始化

	int minNum;		//最小线程数
	int maxNum;		//线程池最大线程数

	int exitNum;	//需取消的线程数

	pthread_mutex_t mutexPool;	//互斥访问线程池、
	pthread_cond_t notEmpty;		//生产者消费者模型,条件变量

	bool shutdown=false;			//关闭线程池否
	static const int NUMBER = 2;		//线程池中增加线程时每次增NUMBER个
public:
	//创建线程池、初始化
	Threadpool(int& min, int& max);

	~Threadpool();

	int addTask(Task task);
	//内部已加锁,互斥操作
	int getBusyNum();
	//互斥操作
	int getAliveNum();
	//

private:
	//wroker:工作者线程将任务(回调函数、参数)从任务队列中取出,并执行,即调用Task的function函数
	//静态成员函数只能访问静态成员变量,
	static void* worker(void* arg);
	static void* manager(void* arg);
	void threadExit();
	int busyNum;		//在工作的线程数,(动态改变频率高,需要加锁
	int liveNum;

};

三、test.cpp

示例代码如下:

#include "threadpool.h"
using namespace std;

void function(void* arg) {
	int num = *(int*)arg;
	printf("thread:%ld,working..num=%d", pthread_self(), num);
	sleep(1);
}
int main() {
	int b = 3,d=10,m=0;
	int& a = b,&c=d;
	Threadpool pool(a, c);
	for (int i = 0; i < 100; i++) {
		int* num = new int(i + 100);
		m = pool.addTask(Task(function, num));
		if (m<0) {
			std::cout << "pool.addtask failed "<< m<<"\n" << std::endl;
			return -1;
		}
	}
	sleep(20);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值