C++11线程池

线程池其实就是把任务队列和工作线程绑到一起,提供一个向任务队列中添加任务的接口,下面的代码为了表达更加清楚没有分成头文件和源文件,仅仅是提供思路。

同步机制利用的互斥锁+条件变量,也可以使用C++11提供的原子数封装的自旋锁+条件变量。两种组合的区别在于,自旋锁比较适合当任务比较简单的时候使用,可以减少陷入内核的次数,但当任务比较复杂,线程需要较长时间等待的时候,自旋锁会把大量时间浪费在忙等待上,此时用互斥锁比较好。

#include<condition_variable>
#include<mutex>
#include<thread>
#include<vector>
#include<queue>
#include<memory>
using namespace std;

class ThreadPool
{
public:
	typedef std::function<void()> Task;

	explicit ThreadPool(size_t threadnum,size_t tasknum)
		:running_(false),
		 maxQueueSize_(tasknum),
		 maxThreads_(threadnum)
	{ }									//用的C++11封装好的线程类,锁,条件变量
	~ThreadPool()
	{
		if(running_)
			stop();
	}
	void stop()							//停止,其实没啥用,没指望线程池能正常退出
	{
		{
			lock_guard<mutex>lg(mutex_);
			running_=false;
			notEmpty_.notify_all();
		}
		for(auto& thr:threads_)
			thr->join();
	}
	void start()						//启动工作队列
	{
		running_=true;
		threads_.reserve(maxThreads_);
		for(int i=0;i<maxThreads_;i++)
		{
			threads_.emplace_back(thread(runInThread,this));
			threads_[i]->detach();
		}
	}
	void run(Task task)					//外界向任务队列添加任务的接口
	{
		unique_lock<mutex>ul(mutex_);
		notFull_.wait(ul,[this]{ return queue_.size()<maxQueueSize_; });
		queue_.push(move(task));
		notEmpty_.notify_one();
	}
private:
	bool isFull()const
	{
		lock_guard<mutex>lg(mutex_);
		return queue_.size()>=maxQueueSize_;
	}
	void runInThread()					//工作线程的任务就是从任务队列中取任务,执行,没有任务就阻塞在take中
	{
		while(running_)
		{
			Task task(take());
			if(task)
				task();
		}
	}
	Task take()							//从任务队列中取任务
	{
		unique_lock<mutex>ul(mutex_);
		notEmpty_.wait(ul,[this]{ return queue_.empty(); });
		Task task;
		if(!queue_.empty())
		{
			task=queue_.front();
			queue_.pop();
			notFull_.notify_one();
		}
	}

	mutable mutex mutex_;
	condition_variable notEmpty_;			//本线程池设置了最大任务数量,所以用了两个条件变量
	condition_variable notFull_;
	vector<unique_ptr<thread>> threads_;	//线程实体
	queue<Task> queue_;						//任务队列
	size_t maxQueueSize_;
	size_t maxThreads_;
	bool running_;
};

猜你喜欢

转载自blog.csdn.net/qq_33113661/article/details/89043736