在C++11标准库中,并没有线程池的标准实现,这一章都是作者利用已有的设施,
先实现一个最基本的线程池,然后不断增加一些功能。
以下我就列出它每个小节的内容。
1.线程池
9.1.1简单的线程池
(1)
最简单的线程池,私有成员包括:线程队列与工作队列
接口函数就是:任务提交submit函数。
(2)
任务队列:thread_safe_queue<std::function<void ()>>
提交函数:直接以f构建一个std::function对象,然后push进任务队列,没有返回值。
9.1.2等待任务结束(而非线程结束)的线程池
(1)
等待任务结束,是靠future来实现的,而返回future需要使用std::packaged_task<>,但是std::packaged_task<>实例只是可移动的,
而std::function<>需要函数对象是可以拷贝和构造的,所以需要手动增加一个function_wrapper类。
(2)
任务队列:thread_safe_queue<function_wrapper>
提交函数:以f构建一个std::packaged<>,取得一个future,再作为submit的返回,实现等待任务结束的功能
9.1.4避免工作队列上的竞争
解决办法就是维护一个自己的thread_local的任务队列,
往线程池里面添加任务添加到全局任务队列
线程池里面的线程在递归调用产生新任务的时候,往自己的工作队列添加任务。
执行的时候,当自己的thead_local的任务队列里面没有任务的时候才向全局任务队列取任务。
9.1.5工作窃取
为了应对工作分配不均,可以允许线程在自己任务,以及公共任务做完以后可以窃取别人的任务来完成。
每一个窃取队列是一个对于std::deque<function_warpper>的再封装,
自己使用时从队首弹任务,窃取时从队尾弹任务,这样可最大化并发,所以采用deque。
由于工作窃取的时候并不多,所以这个队列采用简单的mutex机制保证并发安全。
2.线程中断
既然连线程池都没有实现为标准库,这个也是没有的。需要自己构建。
这里的线程中断,本质上就是一种线程间通信。
(1)中断发起,调用中断函数interrupt(),这个函数会设置interrupt_flag对象。
(2)中断检测,线程在想要查看是否被中断的地方调用interruption_point(),这个函数会查看interrupt_flag,如果被置位,就throw一个异常。
(3)在阻塞过程(条件变量的wait,future等待)中检测中断,这个其实是伪命题。文中解决办法是,细粒化这种阻塞,在中间调用interrupttion_point()。
(4)中断处理,正常try-catch即可。