C++11线程池ThreadPool(模仿Java的ThreadPoolExecutor)

功能描述

实现一种基于C++11的线程池ThreadPool,模仿Java的ThreadPoolExecutor;

使用示例

#include"ThreadPool.h"
#include<iostream>
#include<assert.h>
using namespace std;
using Task = std::function<void()>;

std::mutex mx;
void func() {
	this_thread::sleep_for(std::chrono::milliseconds(20));
}
int main() {
	ThreadPool<Task, ArrayBlockingQueue<Task*>> threadPool(5, 10, 500, std::unique_ptr<ArrayBlockingQueue<Task*>>(new ArrayBlockingQueue<Task*>(200)));
	int success = 0;
	int total = 300;
	for (int i = 0; i < total; ++i) {
		Task task = std::bind(func);
		bool flag = threadPool.execute(task);
		std::cout << (flag ? "success" : "failed") << std::endl;
		success += flag;
		std::cout << threadPool.workerCount() << std::endl;
	}
	std::cout << "success/total: " << success << "/" << total << std::endl;
	std::this_thread::sleep_for(std::chrono::milliseconds(5000));
	std::cout << threadPool.workerCount() << std::endl;
}

关键函数说明

创建阻塞队列BlockingQueue

1)ArrayBlockingQueue实现了基于std::queue的有界阻塞队列;
2)参照该模板类的必要函数,用户可以根据阻塞队列类型不同,实现不同类型的阻塞队列(如:有界队列、无界队列、并发队列等);
3)为什么不写一个BlockingQueue抽象类供继承?
因为C++目前对于模板类中的模板函数不可以是虚函数;

ArrayBlockingQueue(int maxSize);

创建线程池ThreadPool

1)WorkQueuePtr为std::unique_ptr<BlockingQueue>类型;
2)其中BlockingQueue为阻塞队列,目前采用模板方式定义;
3)BlockingQueue放置的类型为Task*;
3)目前BlockingQueue仅仅实现了基于std::queue的有界阻塞队列;

	//corePoolSize:核心线程数;  当corePoolSize=0时,只有queue中放不下时,才会创建非核心线程
	//maximumPoolSize:最大线程数;  
	//keepAliveTime:活跃时间(单位毫秒);
	//workQueuePtr:阻塞队列;
	ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, WorkQueuePtr&& workQueuePtr);

提交任务

1)Task为执行的任务类型,为模板类型;
2)返回值表示是否成功添加到队列中或被线程执行;

    //执行任务
	//返回为false的可能情况:队列中满了,且线程数量已经达到最大值
	bool execute(Task& task);

shutdown线程池

	//关闭线程池,线程中当前的任务会执行完,但不会继续取任务队列中的任务
	//是否需要支持暂停添加任务??
	void shutdown();

设计思想

BlockingQueue设计

1)该类实例以组合的方式被ThreadPool持有,主要是为了让用户可以传入自定义的BlockingQueue,提高ThreadPool的扩展性;
2)BlockingQueue放置的类型为Task*;

execute执行流程

1)判断当前核心线程数是否达到极限corePoolSize,如果没有,则创建核心线程并负责执行该任务,并返回true;(执行完这个任务之后,会阻塞在queue上取任务,直到返回)
2)否则,尝试加入BlockingQueue中,成功,则返回true;
3)否则,判断当前线程数达到极限maximumPoolSize,如果没有,则创建非核心线程并负责执行该任务,并返回true;(执行完这个任务之后,会阻塞在queue上取任务,直到返回;当等待超时keepAliveTime后,该线程退出,并销毁对应资源)
4)否则,返回false,表示任务提交失败;
注:执行过程中会判断当前线程池的状态是否为Running,如果不是,也是直接返回false;
注:只有在核心线程数量达到极限corePoolSize且队列BlockingQueue中push失败,才会创建非核心线程;

ctl变量设计

1)ctl类型为atomic_uint32_t,存储线程池状态以及当前线程数量;
2)ctl前3位表示当前ThreadPool状态,后COUNT_BITS=29位表示当前线程数量;
3)如此设计,是为了在方便一起对线程状态以及线程数进行CAS,以避免无意义地持有mainLock;

BlockingQueue必须实现函数说明

1)为适配ThreadPool,以下为用户自定义的BlockingQueue需要实现的函数;
2)其中interrupt()唤醒等待在具有Predicate参数 的push或者pop函数的线程;
3)interrupt()设计目的是唤醒等待在queue上的线程,使得主线程可以通知线程退出;

	const static int SUCCESS = 0;   //成功
	const static int TIMEOUT = 1;  //超时
	const static int INTERRUPT = 2;  //中断;当传入的Predicate为真时,返回(被interrupt唤醒)
	const static int RETRY = 3;  //请重试

	bool isEmpty();
	bool isFull();
	int size();

	int push(Task& task);
	int pop(Task& task);

	template<typename Predicate>
	int push(Task& task, Predicate pred);
	template<typename Predicate>
	int pop(Task& task, Predicate pred);

	bool tryPush(Task& task);
	bool tryPop(Task& task);

	int push(Task& task, int timeout);
	int pop(Task& task, int timeout);

	template<typename Predicate>
	int push(Task& task, int timeout, Predicate pred);
	template<typename Predicate>
	int pop(Task& task, int timeout, Predicate pred);

	void interrupt(); //仅仅打断,仅影响wait的pred

Task类型实现要求

1)可以直接使用Task()的形式进行执行;
2)一种符合要求的Task如下;

using Task = std::function<void()>;

源码

BlockingQueue.h

#pragma once
#include<thread>
#include<queue>
#include<mutex>
#include<condition_variable>

//类型Task支持nullptr的赋值和相等操作
//采用queue+mutex实现有界队列
template<typename Task>
class ArrayBlockingQueue{
public:
	const static int SUCCESS = 0;   //成功
	const static int TIMEOUT = 1;  //超时
	const static int INTERRUPT = 2;  //中断;当传入的Predicate为真时,返回(被interrupt唤醒)
	const static int RETRY = 3;  //请重试
private:
	std::queue<Task> queue;
	int maxSize;

	std::mutex mx;
	std::condition_variable p_cond;  //生产者cond
	std::condition_variable c_cond;  //消费者cond

	ArrayBlockingQueue(const ArrayBlockingQueue&) = delete;
	ArrayBlockingQueue& operator=(const ArrayBlockingQueue&) = delete;

public:
	ArrayBlockingQueue(int maxSize):maxSize(maxSize){}

	bool isEmpty() { return queue.size() == 0; }
	bool isFull() { return queue.size() >= maxSize; }
	int size() { return queue.size(); }

	int push(Task& task);
	int pop(Task& task);

	template<typename Predicate>
	int push(Task& task, Predicate pred);
	template<typename Predicate>
	int pop(Task& task, Predicate pred);

	bool tryPush(Task& task);
	bool tryPop(Task& task);

	int push(Task& task, int timeout);
	int pop(Task& task, int timeout);

	template<typename Predicate>
	int push(Task& task, int timeout, Predicate pred);
	template<typename Predicate>
	int pop(Task& task, int timeout, Predicate pred);

	void interrupt(); //仅仅打断,仅影响wait的pred
};

template<typename Task>
int ArrayBlockingQueue<Task>::push(Task& task) {
	std::unique_lock<std::mutex> lock(mx);
	p_cond.wait(lock, [&]() {return !isFull(); });
	queue.push(task);
	c_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
int ArrayBlockingQueue<Task>::pop(Task& task) {
	std::unique_lock<std::mutex> lock(mx);
	c_cond.wait(lock, [&]() {return !isEmpty(); });
	task = queue.front();
	queue.pop();
	p_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
template<typename Predicate>
int ArrayBlockingQueue<Task>::push(Task& task, Predicate pred) {
	std::unique_lock<std::mutex> lock(mx);
	p_cond.wait(lock, [&]() {return !isFull() || pred(); });
	if (isFull() || pred()) return INTERRUPT;  //被打断
	queue.push(task);
	c_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
template<typename Predicate>
int ArrayBlockingQueue<Task>::pop(Task& task, Predicate pred) {
	std::unique_lock<std::mutex> lock(mx);
	c_cond.wait(lock, [&]() {return !isEmpty() || pred(); });
	if (isEmpty() || pred()) return INTERRUPT;  //被打断
	task = queue.front();
	queue.pop();
	p_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
bool ArrayBlockingQueue<Task>::tryPush(Task& task) {
	std::unique_lock<std::mutex> lock(mx, std::try_to_lock_t());
	if (lock.owns_lock() && !isFull()) {
		queue.push(task);
		c_cond.notify_one();
		return SUCCESS;
	}
	return RETRY;
}

template<typename Task>
bool ArrayBlockingQueue<Task>::tryPop(Task& task) {
	std::unique_lock<std::mutex> lock(mx, std::try_to_lock_t());
	if (lock.owns_lock() && !isEmpty()) {
		task = queue.front();
		queue.pop();
		p_cond.notify_one();
		return SUCCESS;
	}
	return RETRY;
}

template<typename Task>
int ArrayBlockingQueue<Task>::push(Task& task, int timeout) {
	std::unique_lock<std::mutex> lock(mx);
	bool flag = p_cond.wait_for(lock, std::chrono::milliseconds(timeout), [&]() {return !isFull(); });
	if (!flag) return TIMEOUT;
	queue.push(task);
	c_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
int ArrayBlockingQueue<Task>::pop(Task& task, int timeout) {
	std::unique_lock<std::mutex> lock(mx);
	bool flag = c_cond.wait_for(lock, std::chrono::milliseconds(timeout), [&]() {return !isEmpty(); });
	if (!flag) return TIMEOUT;
	task = queue.front();
	queue.pop();
	p_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
template<typename Predicate>
int ArrayBlockingQueue<Task>::push(Task& task, int timeout, Predicate pred) {
	std::unique_lock<std::mutex> lock(mx);
	bool flag = p_cond.wait_for(lock, std::chrono::milliseconds(timeout), [&]() {return !isFull() || pred(); });
	if (!flag) return TIMEOUT;
	if (isFull() || pred()) return INTERRUPT;  //被打断
	queue.push(task);
	c_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
template<typename Predicate>
int ArrayBlockingQueue<Task>::pop(Task& task, int timeout, Predicate pred) {
	std::unique_lock<std::mutex> lock(mx);
	bool flag = c_cond.wait_for(lock, std::chrono::milliseconds(timeout), [&]() {return !isEmpty() || pred(); });
	if (!flag) return TIMEOUT;
	if (isEmpty() || pred()) return INTERRUPT;  //被打断
	task = queue.front();
	queue.pop();
	p_cond.notify_one();
	return SUCCESS;
}

template<typename Task>
void ArrayBlockingQueue<Task>::interrupt() {
	//需要加锁
	//避免线程A在cond.wait()执行pred()后,线程B调用notify,然后线程A阻塞在cond上;这会使得线程A无法知道pred()条件已经被更新
	std::unique_lock<std::mutex> lock(mx); 
	p_cond.notify_all();
	c_cond.notify_all();
}

ThreadPool.h

#pragma once
#include<atomic>
#include<unordered_set>
#include<mutex>
#include<thread>
#include<condition_variable>
#include<functional>
#include<iostream>
#include"BlockingQueue.h"

//类型Task支持nullptr的赋值和相等操作
template<typename Task,typename BlockingQueue= ArrayBlockingQueue<Task*>>
class ThreadPool {
public:
	//using Task = std::function<void()>;
	//using BlockingQueue = BlockingQueue<Task>;
	using WorkQueuePtr = std::unique_ptr<BlockingQueue>;

private:

	//工作者
	class Worker {
	private:
		ThreadPool* threadPoolPtr;  //线程池句柄
		Task* taskPtr;  //任务
		bool isCore;  //是否为核心线程
		int completeTask = 0;  //已完成任务数
		std::thread thread;  //线程
		friend class ThreadPool;
	public:
		Worker(ThreadPool* threadPoolPtr, Task* firstTask, bool isCore):
			threadPoolPtr(threadPoolPtr), taskPtr(firstTask), isCore(isCore), thread(&Worker::work,this)
		{
			if (thread.joinable())
				thread.detach();
		}
		~Worker() {}

		bool isCoreThread() { return isCore; }

		void work() {
			threadPoolPtr->runWorker(this);
		}
	};

	//尝试创建新线程
	bool addWorker(Task* firstTask, bool isCore);

	//worker调用
	void runWorker(Worker* workerPtr);

	void dieThreadHandle(Worker* workerPtr);

public:
	//corePoolSize:核心线程数;  当corePoolSize=0时,只有queue中放不下时,才会创建非核心线程
	//maximumPoolSize:最大线程数;  
	//keepAliveTime:活跃时间(单位毫秒);
	//workQueuePtr:阻塞队列;
	ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, WorkQueuePtr&& workQueuePtr);
	~ThreadPool();

	bool isRunning() { return isRunning(ctl); }
	bool isShutDown() { return isShutDown(ctl); }
	uint32_t workerCount() { return workerCount(ctl); }

	//关闭线程池,线程中当前的任务会执行完,但不会继续取任务队列中的任务
	//是否需要支持暂停添加任务??
	void shutdown();

	//执行任务
	//返回为false的可能情况:队列中满了,且线程数量已经达到最大值
	bool execute(Task& task);

private:
	bool isRunning(uint32_t c) { return (c >> COUNT_BITS) == RUNNING; }
	bool isShutDown(uint32_t c) { return (c >> COUNT_BITS) == SHUTDOWN; }
	uint32_t workerCount(uint32_t c) { return c & CAPACITY; }

	ThreadPool(const ThreadPool&) = delete;
	ThreadPool& operator=(const ThreadPool&) = delete;

	const static uint32_t INT32_COUNT = 32;  //ctl位数
	const static uint32_t COUNT_BITS = INT32_COUNT - 3;  //前3位为状态码
	const static uint32_t CAPACITY = (1 << COUNT_BITS) - 1;  //最大线程数

	//状态码
	const static uint32_t RUNNING = 0;
	const static uint32_t SHUTDOWN = 1;
	const static uint32_t STOP = 2;

	int corePoolSize;  //核心线程数
	int maximumPoolSize;  //最大线程数
	int keepAliveTime;  //活跃时间(单位毫秒),作用:使得非核心线程在空闲时退出
	WorkQueuePtr workQueuePtr;  //工作队列

	std::mutex mainLock; 
	std::condition_variable die_cond; //作用:通知线程退出(正常析构销毁对象)

	std::unordered_set<Worker*>workerPtrs;  //工作者

	std::atomic_uint32_t ctl;  //将状态和线程数放在一起,方便CAS;当前状态(3位)+当前线程数
};


//尝试创建新线程
template<typename Task, typename BlockingQueue>
bool ThreadPool<Task, BlockingQueue>::addWorker(Task* firstTask, bool isCore) {
	while (true) {
		auto c = ctl.load();
		if (!isRunning(c)) return false;
		int wc = workerCount(c);
		if (wc >= (isCore ? corePoolSize : maximumPoolSize))
			return false;
		if (ctl.compare_exchange_strong(c, c + 1))//CAS
			break;
	}
	std::lock_guard<std::mutex> lock(mainLock);
	if (!isRunning()) {
		--ctl;
		die_cond.notify_all();  //使得threadpool正常析构
		return false;
	}
	Worker* workerPtr = new Worker(this, firstTask, isCore);
	workerPtrs.insert(workerPtr);
	return true;
}

//worker调用
template<typename Task, typename BlockingQueue>
void ThreadPool<Task, BlockingQueue>::runWorker(Worker* workerPtr) {
	if (workerPtr == nullptr) return;
	if (workerPtr->taskPtr != nullptr) {
		(*workerPtr->taskPtr)();
		++workerPtr->completeTask;
		delete workerPtr->taskPtr;
		workerPtr->taskPtr = nullptr;
	}
	int flag = 0;
	while (isRunning()) {
		if (!workerPtr->isCoreThread()) {
			flag = workQueuePtr->pop(workerPtr->taskPtr, keepAliveTime, [&]() {return !isRunning(); });
			if (flag == BlockingQueue::TIMEOUT)
				break;
		}
		else
			flag = workQueuePtr->pop(workerPtr->taskPtr, [&]() {return !isRunning(); });
		if (flag == BlockingQueue::SUCCESS && workerPtr->taskPtr!=nullptr) {
			(*workerPtr->taskPtr)();
			++workerPtr->completeTask;
		}
		if (workerPtr->taskPtr != nullptr) {
			delete workerPtr->taskPtr;
			workerPtr->taskPtr = nullptr;
		}
	}
	dieThreadHandle(workerPtr);
}

template<typename Task, typename BlockingQueue>
void ThreadPool<Task, BlockingQueue>::dieThreadHandle(Worker* workerPtr) {
	std::lock_guard<std::mutex> lock(mainLock);
	workerPtrs.erase(workerPtr);
	--ctl;
	delete workerPtr;
	die_cond.notify_all();
}

//corePoolSize:核心线程;
//maximumPoolSize:最大线程;
//keepAliveTime:活跃时间(单位毫秒);
//workQueuePtr:阻塞队列;
template<typename Task, typename BlockingQueue>
ThreadPool<Task, BlockingQueue>::ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, WorkQueuePtr&& workQueuePtr) :
	corePoolSize(corePoolSize), maximumPoolSize(maximumPoolSize),
	keepAliveTime(keepAliveTime), workQueuePtr(std::move(workQueuePtr)), ctl(0)
{

}

template<typename Task, typename BlockingQueue>
ThreadPool<Task, BlockingQueue>::~ThreadPool() {
	shutdown();
	std::unique_lock<std::mutex> lock(mainLock);
	die_cond.wait(lock, [&]() {return workerCount() == 0; });
	Task* taskPtr = nullptr;
	while (!workQueuePtr->isEmpty()) {
		workQueuePtr->tryPop(taskPtr);
		if (taskPtr != nullptr) {
			delete taskPtr;
			taskPtr = nullptr;
		}
	}
	
}

template<typename Task, typename BlockingQueue>
void ThreadPool<Task, BlockingQueue>::shutdown() {
	if (isShutDown()) return;
	//CAS
	//在特殊情况下,在设置shutdown后,依然有些任务可以正常加入queue中
	while (true) {
		auto expected = ctl.load();
		auto desired = (SHUTDOWN << COUNT_BITS) | (expected & CAPACITY);
		if (ctl.compare_exchange_strong(expected, desired))  //将状态设置为SHUTDOWN
			break;
	}
	//唤醒等待在queue上的队列
	workQueuePtr->interrupt();
}

template<typename Task, typename BlockingQueue>
bool ThreadPool<Task, BlockingQueue>::execute(Task& task) {
	Task* taskPtr = new Task(task);
	auto c = ctl.load();
	auto wc = workerCount(c);
	//当前线程小于corePoolSize,并且成功放入workQueuePtr;
	if (wc < corePoolSize) {
		if (addWorker(taskPtr, true)) return true;
		//此时,ctl变化
		c = ctl.load();
	}
	//当前处于运行状态,且成功加入队列
	if (isRunning(c) && workQueuePtr->tryPush(taskPtr) == BlockingQueue::SUCCESS) {
		return true;
	}
	//尝试开新线程
	return addWorker(taskPtr, false);
}


码云链接

ThreadPool.h
BlockingQueue.h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值