C++ 线程池的思想

参考:https://zhuanlan.zhihu.com/p/367309864

线程池原理总结

首先你要有一个队列来保存你的任务,任务就是待执行的函数,这个队列叫做同步队列,主要就是队列的操作都带上锁实现线程安全。然后需要创建多个线程(可以保存在vector中,这就是线程池),每个线程创建的时候船用执行函数run(),在执行函数run()中,我们不断取出同步队列中的任务来执行,直到完成所有任务,并且主动销毁线程。

#include <mutex>
#include <queue>
#include <functional>
#include <future>
#include <thread>
#include <utility>
#include <vector>
#include <vector>
#include <iostream>
using namespace std;
// Thread safe implementation of a Queue using a std::queue
template <typename T>
class SafeQueue
{
private:
	std::queue<T> m_queue; //利用模板函数构造队列
	std::mutex m_mutex;// 访问互斥信号量
public:
	SafeQueue() {}
	SafeQueue(SafeQueue&& other) {}
	~SafeQueue() {}
	bool empty() // 返回队列是否为空
	{
		std::unique_lock<std::mutex> lock(m_mutex); // 互斥信号变量加锁,防止m_queue被改变
		return m_queue.empty();
	}
	int size()
	{
		std::unique_lock<std::mutex> lock(m_mutex); // 互斥信号变量加锁,防止m_queue被改变
		return m_queue.size();
	}
	// 队列添加元素
	void enqueue(T& t)
	{
		std::unique_lock<std::mutex> lock(m_mutex);
		m_queue.emplace(t);
	}
		// 队列取出元素
	bool dequeue(T& t)
	{
		std::unique_lock<std::mutex> lock(m_mutex); // 队列加锁
		if (m_queue.empty()) return false;
		t = std::move(m_queue.front()); // 取出队首元素,返回队首元素值,并进行右值引用
		m_queue.pop(); // 弹出入队的第一个元素
		return true;
	}
};

class ThreadPool
{
public:

	bool m_shutdown;                          // 线程池是否关闭
	SafeQueue<std::function<void()>> m_queue; // 同步安全队列
	std::vector<std::thread> m_threads; // 工作线程队列
	std::mutex m_conditional_mutex; // 线程休眠锁互斥变量
	std::condition_variable m_conditional_lock; // 线程环境锁,可以让线程处于休眠或者唤醒状态

	ThreadPool(int threadNum = 4) :m_threads(std::vector<std::thread>(threadNum)), m_shutdown(false)
	{
		for (int i = 0; i < threadNum;i++)
		{
			m_threads.at(i) = std::thread(&ThreadPool::runThread,this);
		}

	}
	~ThreadPool()
	{
		shutdown();
	}

	void runThread()
	{
		std::function<void()> func; // 定义基础函数类func
		bool dequeued; // 是否正在取出队列中元素
		while (!this->m_shutdown)
		{
			{
				// 为线程环境加锁,互访问工作线程的休眠和唤醒
				std::unique_lock<std::mutex> lock(this->m_conditional_mutex);

				if (this->m_queue.empty())// 如果任务队列为空,阻塞当前线程
				{
					this->m_conditional_lock.wait(lock); // 等待条件变量通知,开启线程
				}
				// 取出任务队列中的元素
				dequeued = this->m_queue.dequeue(func);
			}
			// 如果成功取出,执行工作函数
			if (dequeued)
				func();
		}
	}

	void shutdown()
	{
		m_shutdown = true;
		m_conditional_lock.notify_all(); // 通知,唤醒所有工作线程
		for (int i = 0; i < m_threads.size(); ++i)
		{
			if (m_threads.at(i).joinable()) // 判断线程是否在等待
			{
				m_threads.at(i).join(); // 将线程加入到等待队列
			}
		}
	}

	//这是一个提交任务的函数,用到了比较多的C++11特性
	template <typename F, typename... Args>
	auto submit(F&& f, Args&&...args) -> std::future<decltype(f(args...))>
	{
		// Create a function with bounded parameter ready to execute
		std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...); // 连接函数和参数定义,特殊函数类型,避免左右值错误

		auto task_ptr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(func);
		std::function<void()> warpper_func = [task_ptr]()
		{
			(*task_ptr)();
		};
		m_queue.enqueue(warpper_func);
		m_conditional_lock.notify_one();
		return task_ptr->get_future();
	}
};

std::mutex m_mutex;
void printValue(int i)
{
	std::unique_lock<std::mutex> lock(m_mutex);
	std::cout << "current thread id : " << std::this_thread::get_id() << std::endl;
	std::cout << "this print value  : " << i << std::endl;
}
int main()
{
	ThreadPool pool(3);
	for (int i = 0; i < 30; i++)
	{
		pool.submit(printValue, i);
	}
	while (1)
	{
		std::this_thread::sleep_for(std::chrono::seconds(60));
	}

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值