简单的线程池(七)
◆ 概要
本文中,笔者为 《简单的线程池(四)》 提及的非阻塞独占式线程池增加了一项功能:当某个工作线程的任务队列中无工作任务时,此工作线程可以去其他工作线程的任务队列中获取任务。笔者称之为非阻塞互助式线程池。
笔者对比了测试结果与 《简单的线程池(六)》 的数据,得出了添加功能前后的差异。
本文不再赘诉与 《简单的线程池(四)》 相同的内容。如有不明之处,请参考该博客。
◆ 实现
以下代码给出了此线程池的实现,(lockwise_mutual_pool.h)
class Thread_Pool { private: struct Task_Wrapper { ... }; atomic<bool> _suspend_; atomic<bool> _done_; unsigned _workersize_; thread* _workers_; Lockwise_Queue<Task_Wrapper>* _workerqueues_; void work(unsigned index) { Task_Wrapper task; while (!_done_.load(memory_order_acquire)) { if (_workerqueues_[index].pop(task)) task(); else // # 1 for (unsigned i = 0; i < _workersize_; ++i) if (_workerqueues_[(index + i + 1) % _workersize_].pop(task)) { // #2 task(); break; } while (_suspend_.load(memory_order_acquire)) std::this_thread::yield(); } } void stop() { ... } public: Thread_Pool() : _suspend_(false), _done_(false) { .... } ~Thread_Pool() { ... } template<class Callable> future<typename std::result_of<Callable()>::type> submit(Callable c) { ... } };
此线程池的代码与 非阻塞独占式线程池 相比,仅在工作线程的初始函数 Thread_Pool::work(unsigned) 上有区别。当某个工作线程的任务队列中无工作任务时(#1),此工作线程会去其他工作线程的任务队列中获取任务。这里涉及到的“选择其他工作线程的任务队列的算法”(#2),来自于本文最后的参考书籍。
◆ 逻辑
此线程池的结构和与 《简单的线程池(四)》 中的一致,此处略。
此线程池用户提交任务与工作线程执行任务的并发过程与 《简单的线程池(一)》 中的一致,此处略。
◆ 验证
验证过程采用了 《简单的线程池(三)》 中定义的的测试用例。笔者对比了测试结果与 《简单的线程池(六)》 的数据,结果如下,
图1 列举了 吞吐量1的差异 在 0.5 分钟、1 分钟和 3 分钟的提交周期内不同思考时间上的对比。
【注】非阻塞互助式 略称为 LM ,下同。
可以看到,
- 当思考时间为 0 时,LM 的吞吐量优于 LS、BS 的吞吐量,相当于 LU、BU 的吞吐量;延长提交周期后,LM 和 LS、BS、LU、BU 的吞吐量差异没有发生明显变化;
- 当思考时间不为 0 时,LM 的吞吐量大幅优于 LS、LU 的吞吐量,大幅劣于 BS、BU 的吞吐量,但差异不会因提交周期的延长而大幅变化;随着思考时间的增加,LM 的吞吐量与 LS、BS、LU、BU 的吞吐量差异逐渐消失。
图2 列举了 吞吐量2的差异 在 0.5 分钟、1 分钟和 3 分钟的提交周期内不同思考时间上的对比。
可以看到,
- 当思考时间为 0 时,LM 的吞吐量优于 LS、BS、LU、BU 的吞吐量;延长提交周期后,LM 和 LS、BS、LU、BU 的吞吐量差异没有发生明显变化;
- 当思考时间不为 0 时,因 LM 和 LS、BS、LU、BU 的吞吐量均为 0,它们间没有差异。
图3 列举了 吞吐量3的差异 在 0.5 分钟、1 分钟和 3 分钟的提交周期内不同思考时间上的对比。
可以看到,
- 当思考时间为 0 时,LM 的吞吐量相当于 LS、BS、LU 的吞吐量,略劣于 BU 的吞吐量;延长提交周期后,LM 和 LS、BS、LU、BU 的吞吐量差异没有发生明显变化;
- 当思考时间不为 0 时,LM 的吞吐量大幅优于 LS、LU 的吞吐量,大幅劣于 BS、BU 的吞吐量,但差异不会因提交周期的延长而大幅变化;随着思考时间的增加,LM 的吞吐量与 LS、BS、LU、BU 的吞吐量差异逐渐消失。
基于以上的对比分析,笔者认为,在非阻塞式线程池中,
- 互助式的吞吐量指标优于共享式、独占式的吞吐量指标。
◆ 最后
完整的示例代码和测试结果请参考 [github] cnblogs/15710614 。
关于“选择其他工作线程的任务队列的算法”,笔者参考了 C++并发编程实战 / (美)威廉姆斯 (Williams, A.) 著; 周全等译. - 北京: 人民邮电出版社, 2015.6 (2016.4重印) 一书。致 Anthony Williams、周全等译者。
ad8- Linux多线程实践(9) --简单线程池的设计与实现
- 一个简单的线程池
- spring(用ThreadPoolTaskExecutor简单实现线程池)
- 简单Linux C线程池
- Linux下设计一个简单的线程池
- 线程池的简单实现
- 【线程池封装】实现简单回射服务器
- 【C/C++开发】C++实现简单的线程池
- C语言实现简单线程池(转-Newerth)
- linux下c语言简单线程池实现
- [并发并行]_[pthread]_[线程池的简单设计与实现]
- 线程池简单实现
- delphi 一个简单的线程池类 已经初步完善
- 自定义线程池-c#的简单实现
- 线程池的概念及Linux 怎么设计一个简单的线程池
- 一个简单的线程池实现
- Linux C++ 一个线程池的简单实现(附代码)
- 简单线程池的实现--JAVA/Python
- 线程池的介绍及简单实现
- 简单的线程池