C++ 11 一个不到100行的简易线程池的实现

 完整代码在:https://github.com/dyexlzc/wheself/blob/master/lcthread/tpool.cpp

最近查阅了很多资料,在看C11的高级特性,然后开始上手写线程池,因为是第一次写,涉及到的东西也挺多的。主要就是:

1.任务队列的管理:queue

2.线程的建立  thread

3.锁的使用  mutex

4.线程的唤醒  condition_variable

3和4共同来实现对线程的调度。

说说这个的思路吧。

首先,每一个任务都是这样的一个类【我觉得java的这种多线程方式比较灵活,就用了他的设计模式】

class tjob {
	public:
		virtual void run() { cout << "tjob" << endl; };
	};

通过继承并且重写run方法来实现每一个具体任务的功能。我这里用sleep来模拟大量运算

class job2 : public tpool::tjob {
public:
	DWORD time;
	job2(DWORD time) {
		this->time = time;
	}
	void run() {
		//cout << "我要运行"<time<<"ms." << endl;
		Sleep(this->time);
	}
};

建立好任务以后,加入到线程池里面去

pool.addTask(*new job2(1000));

他就能自动运行啦

C++ 11 一个不到100行的简易线程池的实现_第1张图片

主类的设计是这样的【忽略那两个构造函数,他们俩的区别就在于一个给定了线程数,一个自动获取PC上最大物理线程数而已,其他的没什么区别】,我在下面会解释他们的作用

class tpool {
public:
	class tjob {
	public:
		virtual void run() { cout << "tjob" << endl; };
	};
	queue job;//任务列表
	mutex mutex_global,job_mutex;
	condition_variable cv;
	thread *tlist;
	int num_running,n;//任务个数
	//bool if_init;
	tpool(int const &_n):n(_n) {
		//初始化线程池个数
		//if_init = false;
		num_running = 0;
		//job_mutex = new mutex[_n];
		tlist = new thread[_n];
		for (int i = 0; i < _n; i++) {
			tlist[i]=thread([this,i]() {//直接在这里用lambda表达式建立线程
				
				while (1) {
					unique_lock lock(this->job_mutex);
					//while(this->if_init==false)
					this->cv.wait(lock, [this] {
						return !this->job.empty();
					});//等待阻塞线程,直到update中通知状态改变
					if (this->job.size() != 0)
					{
						this->mutex_global.lock();
						tjob* job = this->job.front(); this->job.pop();
						this->mutex_global.unlock();
						lock.unlock();
						this->num_running++;
						job->run();
						this->num_running--;
						cout << i<<"线程运行完毕,当前运行"<num_running<<"/"<n<<"任务,任务队列中还剩余"<job.size()<<"个任务未处理" << endl;

						//this->if_init = false;
					}
					//delete this->job_mutex;
				}
			});

		}
	}
	tpool() {
		int _n = this->core_num();
		this->n = _n;
		//初始化线程池个数
		//if_init = false;
		num_running = 0;
		//job_mutex = new mutex[_n];
		tlist = new thread[_n];
		for (int i = 0; i < _n; i++) {
			tlist[i] = thread([this, i]() {//直接在这里用lambda表达式建立线程

				while (1) {
					unique_lock lock(this->job_mutex);
					//while(this->if_init==false)
					this->cv.wait(lock, [this] {
						return !this->job.empty();
					});//等待阻塞线程,直到update中通知状态改变
					if (this->job.size() != 0)
					{
						this->mutex_global.lock();
						tjob* job = this->job.front(); this->job.pop();
						lock.unlock();
						this->num_running++;
						this->mutex_global.unlock();


						job->run();


						this->mutex_global.lock();
						this->num_running--;
						this->mutex_global.unlock();
						cout << i << "线程运行完毕,当前运行" << this->num_running << "/" << this->n << "任务,任务队列中还剩余" << this->job.size() << "个任务未处理" << endl;

						//this->if_init = false;
					}
					//delete this->job_mutex;
				}
			});

		}
	}
	void addTask(tjob& job) {
		//cout << "添加任务" << endl;
		this->job.push(&job);
		this->update();
		
	}
	void update() {
		//更新线程状态
		this->cv.notify_one();
	}
	unsigned int core_num(){
		return std::thread::hardware_concurrency();
	}

};

先说说成员变量 

queue job;           //任务队列,里面是指针类型的tjob对象,设置为指针类型才能正确调用派生类的run()函数而不是基类的
 mutex mutex_global,job_mutex;    //两个锁,第一个锁是全局锁,也就是说在一些需要操作变量的地方加上,第二个job_mutex是指任务锁,每个线程都会于这个锁关联,他和condition_variable共同实现有任务时对线程的唤醒
 condition_variable cv;  //字面翻译为状态变量,他有两个主要函数notify_one(),notify_all();具体可以查看这篇blog:https://www.cnblogs.com/wangshaowei/p/9593201.html


 thread *tlist;  //使用指针来初始化n个线程,然后重复利用他们
 int num_running,n;//任务个数,用来计算和显示给用户看的

tlist = new thread[_n];
		for (int i = 0; i < _n; i++) {//根据参数建立N个线程用来复用,减少线程建立-》销毁的开销
			tlist[i] = thread([this, i]() {//直接在这里用lambda表达式建立线程

				while (1) {//线程在不断监听,但是它会被下面的wait阻塞住,所以不会占用CPU资源
					unique_lock lock(this->job_mutex);//所有线程公用一个锁,unique_lock
					this->cv.wait(lock, [this] {//cv就是condition_variable,当在其他线程的cv唤醒notify_one()以后,众多线程中的某一个线程就会相应到,于是他就从cv.wait处结束阻塞状态,开始向下运行。
						return !this->job.empty();
					});//等待阻塞线程,直到update中通知状态改变
					if (this->job.size() != 0)    //判断任务列表中是否有任务,有的话就运行
					{
						this->mutex_global.lock();    //因为要对queue进行操作所以必须要加锁!
						tjob* job = this->job.front(); this->job.pop();
						lock.unlock();
						this->num_running++;
						this->mutex_global.unlock();


						job->run();            //得到对象,开始运行任务


						this->mutex_global.lock();
						this->num_running--;
						this->mutex_global.unlock();
						cout << i << "线程运行完毕,当前运行" << this->num_running << "/" << this->n << "任务,任务队列中还剩余" << this->job.size() << "个任务未处理" << endl;

						//this->if_init = false;
					}
					//delete this->job_mutex;
				}
			});

 

你可能感兴趣的:(C++)