C++ 线程池

参考《深入学习C++11》

1概述

1.1设计目标

实现一个线程池,启动时开启n个线程。线程池中的线程从同步消息队列中取任务并执行

1.2线程池的好处

处理并发任务时,如果每来一个请求建立一个线程,大量的线程销毁和创建将消耗过多的系统资源

线程池技术可以通过在系统中预先创建一定数量的线程,当任务到达时从线程池中分配一个预先建立的线程去处理任务,线程在处理完任务之后还可以重用,不会销毁,而是等待下次任务到来,这样就避免了大量线程的创建和销毁动作,从而节省了系统资源

对于多核处理器,多个线程会被分配到多个CPU,提高并行处理的效率

每个线程独立阻塞,可以防止主线程阻塞导致主流程阻塞

1.3设计思路

线程池可以分为三层,同步服务层,排队层和异步服务层

同步服务层负责将上层的请求任务放入排队层

异步服务层从排队层取出任务并行的处理

2实现

2.1同步队列

//syncQueue.h
#pragma once
#include<mutex>
#include<condition_variable>
#include<iostream>
#include<list>

using namespace std;

template<class T>
class syncQueue
{
public:
	syncQueue(int max_size);
	~syncQueue();

	void put(T&x);
	void put(T&& x);

	void take(list<T>& list);
	void take(T& t);

	void stop();
	bool empty();
	bool full();
	size_t size();
	int count();

private:
	void add(T&&x);
	bool notEmpty() const;
	bool notFull() const;

private:
	mutex mmutex;
	condition_variable cv_not_empty;
	condition_variable cv_not_full;
	list<T> queue;
	int max_size;
	bool need_stop;
};

extern mutex printLock;
//syncQueue.cpp
#include "syncQueue.h"

using namespace std;

template<class T>
syncQueue<T>::syncQueue(int max_size) :max_size(max_size), need_stop(0)
{
}

template<class T>
syncQueue<T>::syncQueue::~syncQueue()
{
}

template<class T>
void syncQueue<T>::put(T&x)
{
	add(move(x));
}

template<class T>
void syncQueue<T>::put(T && x)
{
	add(forward<T>(x));
}

template<class T>
void syncQueue<T>::take(list<T>& list)
{
	unique_lock<mutex> locker(mmutex);
	cv_not_empty.wait(locker, [this] {return need_stop || notEmpty(); });
	if (need_stop)
		return;
	list = move(queue);
	cv_not_full.notify_one();
}

template<class T>
void syncQueue<T>::take(T & t)
{
	unique_lock<mutex> locker(mmutex);
	cv_not_empty.wait(locker, [this] {return  need_stop || notEmpty(); });
	if (need_stop)
		return;
	t = queue.front();
	queue.pop_front();
	cv_not_full.notify_one();
}

template<class T>
void syncQueue<T>::stop()
{
	{
		lock_guard<mutex> = locker(mmutex);
		need_stop = true;
	}
	cv_not_empty.notify_all();
	cv_not_full.notify_all();
}

template<class T>
bool syncQueue<T>::empty()
{
	lock_guard<mutex> locker(mmutex);
	return queue.empty();
}

template<class T>
bool syncQueue<T>::full()
{
	lock_guard<mutex> locker(mmutex);
	return queue.size() >= max_size;
}

template<class T>
size_t syncQueue<T>::size()
{
	lock_guard<mutex> locker(mmutex);
	return queue.size();
}

template<class T>
int syncQueue<T>::count()
{
	return queue.size();
}

template<class T>
void syncQueue<T>::add(T&&x)
{
	unique_lock<mutex> locker(mmutex);
	cv_not_full.wait(locker, [this] {return need_stop || notFull(); });
	if (need_stop)
		return;
	queue.emplace_back(forward<T>(x));
	cv_not_empty.notify_one();
}

template<class T>
bool syncQueue<T>::notEmpty() const
{
	bool res = queue.empty();
	if (res)
	if (res)
	{
		lock_guard<mutex> locker(printLock);
		cout << "Queue is empty now, wait a minute..." << endl;
	}	
	return !res;
}

template<class T>
bool syncQueue<T>::notFull() const
{
	bool res = queue.size() >= max_size;
	if (res)
	{
		lock_guard<mutex> locker(printLock);
		cout << "Queue is full, wait a minute..." << endl;
	}
	return !res;
}

同步队列测试代码:

#include <iostream>
#include "syncQueue.cpp"

using namespace std;

int main()
{
	auto p = make_shared<syncQueue<int>>(10);

	while (1)
	{
		int tmp;
		cout << "input a num:" << endl;
		cin >> tmp;
		if (tmp)
			p->put(tmp);
		else
			p->take(tmp);
	}

	system("pause");
	return 0;
}

测试结果:

input a num:
1
input a num:
0
input a num:
0
Queue is empty now, wait a minute...

2.2线程池

//threadPool.h
#pragma once
#include "syncQueue.cpp"
#include <thread>
#include <functional>

const int maxTaskNum = 100;
using Task = function<void()>;

class threadPool
{
public:
	threadPool(int numThreads = thread::hardware_concurrency());
	~threadPool();
	void stop();
	void addTask(Task&&task);

private:
	void start(int numThreads);
	void run();
	void stopThreadGroup();
	syncQueue<Task> queue;
	list<shared_ptr<thread>> threadGroup;
	once_flag flag;
	bool running;
};

extern mutex printLock;
#include "threadPool.h"

using namespace std;

threadPool::threadPool(int numThreads):queue(maxTaskNum)
{
	start(numThreads);
}

threadPool::~threadPool()
{
	stop();
}

void threadPool::stop()
{
	call_once(flag, [this] {stopThreadGroup(); });
}

void threadPool::addTask(Task&&task)
{
	queue.put(forward<Task>(task));
}

void threadPool::start(int numThreads)
{
	running = true;
	for (int i = 0; i < numThreads; i++)
	{
		threadGroup.emplace_back(make_shared<thread>(&threadPool::run, this));
	}
}

void threadPool::run()
{
	while (running)
	{
		list<Task> list;
		queue.take(list);
		for (auto task : list)
		{
			if (!running)
				return;
			{
				lock_guard<mutex> locker(printLock);
				cout << "thread id used this time is: " << this_thread::get_id() << endl;
			}			
			task();
		}
	}
}

void threadPool::stopThreadGroup()
{
	queue.stop();
	running = false;

	for (auto thread : threadGroup)
	{
		if (thread)
			thread->join();
	}

	threadGroup.clear();
}

线程池测试代码:

#include <iostream>
#include <chrono>
#include "threadPool.h"

using namespace std;

mutex printLock;//打印锁,防止打印串行

int main()
{
	/*测试同步队列*/
	//int queue_size = 0;
	//cout << "input queue size:" << endl;
	//cin >> queue_size;
	//auto p = make_shared<syncQueue<int>>(queue_size);

	//while (1)
	//{
	//	int tmp;
	//	cout << "input a num:" << endl;
	//	cin >> tmp;
	//	if (tmp)
	//		p->put(tmp);
	//	else
	//		p->take(tmp);
	//}
	
	/*测试线程池*/
	threadPool pool;
	
	thread t1([&pool] {
		for (int i = 0; i < 5; i++)
		{
			auto id = this_thread::get_id();
			pool.addTask([id] {
				this_thread::sleep_for(chrono::milliseconds(100));
				lock_guard<mutex> locker(printLock);
				cout << "working for thread: " << id << endl; });
		}
	});
	thread t2([&pool] {
		for (int i = 0; i < 5; i++)
		{
			auto id = this_thread::get_id();
			pool.addTask([id] {
				this_thread::sleep_for(chrono::milliseconds(100));
				lock_guard<mutex> locker(printLock);
				cout << "working for thread: " << id << endl; });
		}
	});

	this_thread::sleep_for(chrono::seconds(2));
	pool.stop();
	t1.join();
	t2.join();

	system("pause");
	return 0;
}

测试结果:

Queue is empty now, wait a minute...
Queue is empty now, wait a minute...
Queue is empty now, wait a minute...
Queue is empty now, wait a minute...
Queue is empty now, wait a minute...
thread id used this time is: 16092
thread id used this time is: 17264
Queue is empty now, wait a minute...
thread id used this time is: 11768
Queue is empty now, wait a minute...
working for thread: 6720
thread id used this time is: 16092
working for thread: 6720
thread id used this time is: 17264
working for thread: 4052
thread id used this time is: 11768
working for thread: 6720
thread id used this time is: 16092
working for thread: 6720
thread id used this time is: 17264
working for thread: 4052
Queue is empty now, wait a minute...
working for thread: 4052
thread id used this time is: 16092
working for thread: 6720
Queue is empty now, wait a minute...
working for thread: 4052
thread id used this time is: 16092
working for thread: 4052
Queue is empty now, wait a minute...

发布了17 篇原创文章 · 获赞 22 · 访问量 3036

猜你喜欢

转载自blog.csdn.net/u013536232/article/details/97374854
今日推荐