一个简单的线程池本质上是生产者-消费者模型,一般是线程池负责消费任务,任务分配线程负责生产任务,任务可以由队列、链表或全局变量等数据结构承担。如果生产和消费速度差不多,可以采用环形队列结构;如果任务有优先级别,也可采用多个队列分别存放不同优先级别的任务。线程池的同步一般采用互斥锁和条件变量模式。如果为了追求效率,也可使用无锁队列结构。

实例代码如下:TaskPool.h

#include <thread>
#include <mutex>
#include <condition_variable>
#include <list>
#include <vector>
#include <memory>
#include <iostream>class Task
{
public:virtual void doIt(){std::cout << "handle a task..." << std::endl;}virtual ~Task(){//为了看到一个task的销毁,这里刻意补上其析构函数std::cout << "a task destructed..." << std::endl;}
};class TaskPool final
{
public:TaskPool();~TaskPool();TaskPool(const TaskPool& rhs) = delete;TaskPool& operator=(const TaskPool& rhs) = delete;public:void init(int threadNum = 5);void stop();void addTask(Task* task);void removeAllTasks();private:void threadFunc();private:std::list<std::shared_ptr<Task>>            m_taskList;std::mutex                                  m_mutexList;std::condition_variable                     m_cv;bool                                        m_bRunning;std::vector<std::shared_ptr<std::thread>>   m_threads;
};
TaskPool.cpp
#include "TaskPool.h"TaskPool::TaskPool() : m_bRunning(false)
{}TaskPool::~TaskPool()
{removeAllTasks();
}void TaskPool::init(int threadNum/* = 5*/)
{if (threadNum <= 0)threadNum = 5;m_bRunning = true;for (int i = 0; i < threadNum; ++i){std::shared_ptr<std::thread> spThread;spThread.reset(new std::thread(std::bind(&TaskPool::threadFunc, this)));m_threads.push_back(spThread);}
}void TaskPool::threadFunc()
{std::shared_ptr<Task> spTask;while (true){std::unique_lock<std::mutex> guard(m_mutexList);while (m_taskList.empty()){                 if (!m_bRunning)break;//如果获得了互斥锁,但是条件不满足的话,m_cv.wait()调用会释放锁,且挂起当前//线程,因此不往下执行。//当发生变化后,条件满足,m_cv.wait() 将唤醒挂起的线程,且获得锁。m_cv.wait(guard);}if (!m_bRunning)break;spTask = m_taskList.front();m_taskList.pop_front();if (spTask == NULL)continue;spTask->doIt();spTask.reset();}std::cout << "exit thread, threadID: " << std::this_thread::get_id() << std::endl;
}void TaskPool::stop()
{m_bRunning = false;m_cv.notify_all();//等待所有线程退出for (auto& iter : m_threads){if (iter->joinable())iter->join();}
}void TaskPool::addTask(Task* task)
{std::shared_ptr<Task> spTask;spTask.reset(task);{std::lock_guard<std::mutex> guard(m_mutexList);             m_taskList.push_back(spTask);std::cout << "add a Task." << std::endl;}m_cv.notify_one();
}void TaskPool::removeAllTasks()
{{std::lock_guard<std::mutex> guard(m_mutexList);for (auto& iter : m_taskList){iter.reset();}m_taskList.clear();}
}

上述代码封装了一个简单的任务队列模型,我们可以这么使用这个 TaskPool 对象:

#include "TaskPool.h"
#include <chrono>int main()
{TaskPool threadPool;threadPool.init();Task* task = NULL;for (int i = 0; i < 10; ++i){task = new Task();threadPool.addTask(task);}std::this_thread::sleep_for(std::chrono::seconds(5));threadPool.stop();return 0;
}

演示结果如下:

注:由于退出线程的输出提示不是原子的,多个线程并行执行,因此上图中这部分的输出出现了”错乱“。

一个简单的线程池设计方案相关推荐

  1. 分享:一个简单的线程池的实现

    一个简单的线程池的实现 http://my.oschina.net/hejiula/blog/110519

  2. 手写一个简单的线程池MyThreadPool

    说明 手写的一个简单的线程池,旨在帮助了解线程池的工作原理. 核心内容 核心工作线程 任务阻塞队列 定义一个内部类去实现核心工作线程 /*** 内部类:工作的核心线程*/private final c ...

  3. Linux C 实现一个简单的线程池

    https://www.cnblogs.com/GyForever1004/p/9185240.html 线程池的定义 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动 ...

  4. java中的STL库_C++11 STL线程库实现一个简单的线程池

    使用C++11 STL线程库实现一个线程池.处理机制是抢占式的,即所有线程从一个队列(std::queue)中获取任务执行(计算字符串简单HASH值),使用std::mutex和std::condit ...

  5. Linux下设计一个简单的线程池

    定义 什么是线程池?简单点说,线程池就是有一堆已经创建好了的线程,初始它们都处于空闲等待状态,当有新的任务需要处理的时候,就从这个池子里面取一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放 ...

  6. 用Python实现一个简单的线程池

    线程池的概念是什么? 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是 如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收 ...

  7. 【C/C++开发】C++实现简单的线程池

    C++实现简单的线程池 线程池编程简介: 在我们的服务端的程序中运用了大量关于池的概念,线程池.连接池.内存池.对象池等等.使用池的概念后可以高效利用服务器端的资源,比如没有大量的线程在系统中进行上下 ...

  8. C语言实现简单的线程池【转】

    转自https://blog.csdn.net/hubi0952/article/details/8045094 线程池的基本原理 在传统的服务器结构中,常用一个总的线程监听有没有新的客户端连接服务器 ...

  9. android的线程管理器,[Android开源]:一款安全、轻巧、简单的线程池管理器EasyThread...

    EasyThread通过对原生的线程池进行封装,可让你更方便的进行线程任务操作. 特性 简单轻巧:方法数不过百,无额外次级依赖. 配置灵活:可方便.灵活的对每次所启动的任务,配置线程名.线程优先级等. ...

最新文章

  1. R绘制面积图(area plot)
  2. ACM 配置中心实战:Spring + MyBatis + Druid + ACM
  3. 【Flutter】Flutter 混合开发 ( Dart 代码调试 | Flutter 单独调试 | 混合模式下 Flutter 调试 )
  4. 配置SAMBA文件共享的基本方法
  5. jquery 获取索引值在一定范围的列表
  6. node 报错 throw er; // Unhandled 'error' event 解决办法
  7. Handshake failed due to invalid Upgrade header: null 解决方案
  8. 数源思维完成目标设定
  9. LNMP详解(十四)——Nginx日志详解
  10. ArcGIS学习总结(17)—— 栅格数据条件计算及Con函数应用
  11. hbase 查询固定条数_HBase统计表行数(RowCount)的四种方法
  12. android版本内存卡,版本等级繁多 教你如何挑选手机内存卡
  13. Trister Community DAOs最新型DAO架构
  14. 苹果蓝牙耳机平替哪款最好?四款苹果蓝牙耳机平价替代
  15. vba xla文件宏文件解密
  16. vue配置开发、测试、生产环境(proxy中获取process.env.NODE_ENV)
  17. java计算机毕业设计智友少儿编程学习平台源码+mysql数据库+系统+部署+lw文档
  18. 责任链模式:“张三为了纪念王二请假的悲催经历想出来的一种设计模式”
  19. SQL Server 2005连接服务器时服务器名称填什么?
  20. c语言编程 黑色星期五,求黑色星期五问题~

热门文章

  1. 【李宏毅2020 ML/DL】P51 Network Compression - Knowledge Distillation | 知识蒸馏两大流派
  2. CSS-文本垂直居中
  3. C#控制 计算机中“服务”的启动与停止 转
  4. 当PowerDesigner的工具栏不见时候该怎么调出来
  5. 服务器san 虚拟化安装系统,在Hyper-V中安装iSCSI SAN服务器(下)
  6. SCCM2012系列之六,SCCM2012部署前的WDS准备
  7. 【数据安全案例】花旗集团承认遭受数据安全泄露
  8. log4j配置以及logback配置
  9. imread函数_不知道这 7 大 OpenCV 函数怎么向计算机视觉专家进阶?
  10. Android中Bitmap缓存池