使用C++11实现线程池的两种方法

概述:什么是线程池?

   因为程序边运行边创建线程是比较耗时的,所以我们通过池化的思想:在程序开始运行前创建多个线程,这样,程序在运行时,只需要从线程池中拿来用就可以了.大大提高了程序运行效率.

如何实现:

   一般线程池都会有以下几个部分构成:

1. 线程池管理器(ThreadPoolManager):用于创建并管理线程池
2. 工作线程(WorkThread): 线程池中线程
3. 任务队列:用于存放没有处理的任务。提供一种缓冲机制。
4. 用于添加任务的接口 

总的来讲,就是先创建几个线程,然后这些线程等待任务队列,不为空拿出任务执行即可(任务可以是对象,也可以是某个函数).

第一种实现:

#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <stdexcept>
#include <condition_variable>
#include <memory> //unique_ptr

const int MAX_THREADS = 1000; //最大线程数目

template <typename T>
class threadPool
{
  public:
	/*默认开一个线程*/
	threadPool(int number = 1);
	~threadPool();
	/*往请求队列<task_queue>中添加任务<T *>*/
	bool append(T *request);

  private:
	/*工作线程需要运行的函数,不断的从任务队列中取出并执行*/
	static void *worker(void *arg);
	void run();

  private:
	std::vector<std::thread> work_threads; /*工作线程*/
	std::queue<T *> tasks_queue;		   /*任务队列*/
	std::mutex queue_mutex;
	std::condition_variable condition;  /*必须与unique_lock配合使用*/
	bool stop;
};

template <typename T>
threadPool<T>::threadPool(int number) : stop(false)
{
	if (number <= 0 || number > MAX_THREADS)
		throw std::exception();
	for (int i = 0; i < number; i++)
	{
		std::cout << "创建第" << i << "个线程 " << std::endl;
		/*
		std::thread temp(worker, this);
		不能先构造再插入
		 */
		work_threads.emplace_back(worker, this);
	}
}
template <typename T>
inline threadPool<T>::~threadPool()
{
	/*世上最大 bug 就是因为我写的这个.shit  */
	//work_threads.clear();
	{
		std::unique_lock<std::mutex> lock(queue_mutex);
		stop = true;
	}
	condition.notify_all();
	for (auto &ww : work_threads)
		ww.join();
}
template <typename T>
bool threadPool<T>::append(T *request)
{
	/*操作工作队列时一定要加锁,因为他被所有线程共享*/
	queue_mutex.lock();
	tasks_queue.push(request);
	queue_mutex.unlock();
	condition.notify_one(); //线程池添加进去了任务,自然要通知等待的线程
	return true;
}
template <typename T>
void *threadPool<T>::worker(void *arg)
{
	threadPool *pool = (threadPool *)arg;
	pool->run();
	return pool;
}
template <typename T>
void threadPool<T>::run()
{
	while (!stop)
	{
		std::unique_lock<std::mutex> lk(this->queue_mutex);
		/* unique_lock() 出作用域会自动解锁 */
		this->condition.wait(lk, [this] { return !this->tasks_queue.empty(); });
		//如果任务队列不为空,就停下来等待唤醒
		if (this->tasks_queue.empty())
		{
			continue;
		}
		else
		{
			T *request = tasks_queue.front();
			tasks_queue.pop();
			if (request)
				request->process();
		}
	}
}
#endif

测试代码:

#include "threadPool.h"
#include<string>
using namespace std;
class Task
{
	public:
	void process()
	{
		cout << "run........." << endl;
	}
};
int main(void)
{
	threadPool<Task> pool(6);
    std::string str;
	while (1)
	{
			Task *tt = new Task();
			//使用智能指针
			pool.append(tt);
            delete tt;
    }
}

我测试的时候是没有一点毛病的哦......

第二种实现(适用于需传参,需要将非静态线程函数写在类中的情况):

#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <stdexcept>
#include <condition_variable>
#include <memory> //unique_ptr
#include <functional>

const int MAX_THREADS = 1000; //最大线程数目

typedef std::function<void(void)> Task;

class threadPool
{
  public:
	/*默认开一个线程*/
	threadPool(int number = 1);
	~threadPool();
	/*往请求队列<task_queue>中添加任务<T *>*/
	bool append(Task task);

  private:
	/*工作线程需要运行的函数,不断的从任务队列中取出并执行*/
	static void *worker(void *arg);
	void run();

  private:
	std::vector<std::thread> work_threads; /*工作线程*/
	std::queue<Task> tasks_queue;		   /*任务队列*/

	std::mutex queue_mutex;
	std::condition_variable condition; /*必须与unique_lock配合使用*/
	bool stop;
};

threadPool::threadPool(int number) : stop(false)
{
	if (number <= 0 || number > MAX_THREADS)
		throw std::exception();
	for (int i = 0; i < number; i++)
	{
		std::cout << "创建第" << i << "个线程 " << std::endl;
		work_threads.emplace_back(threadPool::worker, this);
	}
}

inline threadPool::~threadPool()
{
	{
		std::unique_lock<std::mutex> lock(queue_mutex);
		stop = true;
	}
	condition.notify_all();
	for (auto &ww : work_threads)
		ww.join();
}

bool threadPool::append(Task task)
{
	/*操作工作队列时一定要加锁,因为他被所有线程共享*/
	queue_mutex.lock();
	tasks_queue.push(task);
	queue_mutex.unlock();
	condition.notify_one(); //线程池添加进去了任务,自然要通知等待的线程
	return true;
}
void *threadPool::worker(void *arg)
{
	threadPool *pool = (threadPool *)arg;
	pool->run();
	return pool;
}
void threadPool::run()
{
	while (!stop)
	{
		std::unique_lock<std::mutex> lk(this->queue_mutex);
		/* unique_lock() 出作用域会自动解锁 */
		this->condition.wait(lk, [this] { return !this->tasks_queue.empty(); });
		//如果任务队列不为空,就停下来等待唤醒
		if (this->tasks_queue.empty())
		{
			continue;
		}
		else
		{
			Task task = tasks_queue.front();
			tasks_queue.pop();
			task();
		}
	}
}
#endif

测试:

#include "threadPool_2.h"
using namespace std;
class Test
{
  public:
	void process_no_static_bind(const int i, const int j) /*推荐使用*/
	{
		cout << "bind:  i==" << i << " "
			 << "j==" << j << endl;
	}
};
int main(void)
{
	threadPool pool(6);
	Test tt_bind;
	while (true)
	{
		pool.append(std::bind(&Test::process_no_static_bind, &tt_bind, 3, 4));
	}
}

参考:github上star与fork过千的线程池代码,源地址如下.

https://github.com/progschj/ThreadPool

posted @ 2018-11-10 22:57  Tattoo_Welkin  阅读(1837)  评论(0编辑  收藏  举报