超简C++11 线程池

线程池的作用:和内存池一样,减少内核态与用户态之间的切换

用C++11新特性实现的超简版线程池:

#include<thread>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<future>
#include<queue>
#include<iostream>

class ThreadPool {
public:
	std::queue< std::function<void()> > task_queue;
	std::vector<std::thread*> threads;
	std::mutex mtx;
	std::condition_variable cv;
	bool isWork = true;

public:
	ThreadPool(int size = 5) {
		if (size <= 0) return;
		for (int i = 0; i < size; ++i) {
			threads.push_back( new std::thread(
				[=] {
				std::function<void()> task;
					while (isWork) {
						{
							std::unique_lock<std::mutex> lock(mtx);	//先抢到锁的线程获得锁,继续执行
							
                            
                            /*
					1. 线程有锁, 则会执行lambda判断
					1.1 判断为假,交还锁,线程阻塞
					1.2 判断为真,线程拿着锁,继续执行

					2. 收到notify_one
					2.1 没有线程wait,notify_one无用
					2.2 有线程wait,且锁没有被使用,选一个线程,并把锁交给该线程,然后回到1
					2.3 有线程wait,但是没有锁,则cv将会等到锁被交还的时候,才会选一个线程,并把锁交给该线程,然后回到1, 如果在等锁的过程中有线程A进入,则线程A会得到锁吗

					3.  收到notify_all,但是没有锁,则cv将会等到锁被交还的时候,才会选一个线程,并把锁交给该线程,然后回到1
					3.1.没有线程wait,notify_one无用
					2.2 有线程wait,且锁没有被使用,选一个线程,并把锁交给该线程,然后回到1, 
					2.3 有线程wait,但是没有锁,则cv将会等到锁被交还的时候,才会选一个线程,并把锁交给该线程,然后回到1
					3.3 循环2.2 2.3 直到所以notify之前wait的线程都拿到过锁
					*/
							cv.wait(lock, [this] { return !task_queue.empty(); });

							if (task_queue.empty())
								continue;
							
							task = task_queue.front();	//获取任务
							task_queue.pop();
						} //作用域结束,交还锁 

						task();		//任务完成时可执行对象task占用的内存会自动回收
			
					}
				}
			));
			threads[i]->detach();	//启动
		}
	}

	template<class F, class... P>
	auto insertTask(F &&f, P&&... p)-> std::future<decltype( f(p...) )> {

		using taskRetType = decltype( f(p...) );	//获取F的返回类型

		
		auto pkt_task = std::make_shared< std::packaged_task<taskRetType()> >
			( std::bind(std::forward<F>(f), std::forward<P>(p)...) );	

		std::future<taskRetType> ret = pkt_task->get_future();	//获取与任务关联的future
		
		{	//进入临界区,将任务放入任务队列
			std::unique_lock<std::mutex> lock(mtx);
			task_queue.push( [pkt_task]{ (*pkt_task)(); } );
		}

		cv.notify_one();//唤醒被阻塞线程

		return ret;
	}
};

成员变量介绍:

名称类型作用
task_queuestd::queue< std::function<void()> >一个队列,队列的元素为一个可执行对象;该队列会被线程池中的所有线程访问,所以对他的读写要加上锁,写加锁是为了防止数据不一致,读加锁是为了防止同一任务被多个线程执行;同时也应注意在任务执行完成时释放掉可执行对象占用的内存
threadsstd::vector<std::thread*>线程池
mtxstd::mutex互斥量,相当于一把锁
cvstd::condition_variable线程同步,唤醒或者沉睡线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值