线程池
线程池:
一个线程池主要由以下的四个部分构成。
1 线程池管理器,负责创建线程和销毁线程,向工作队列中添加任务等。
2 工作线程,线程池当中负责执行任务的线程,当任务队列为空的情况下,则该线程处于等待的状态。
一般使用信号量来跟踪当先任务队列当中任务的数量,线程处于sem_wait()的状态,等待任务队列为非空
时,竞争的区执行任务。
3 任务接口,任务队列里面的任务都应该实现任务的接口,供工作线程调度执行,最主要的作用就是规
定了任务的入口。
4 任务队列,所有待执行的任务放在任务队列当中,提供了一种缓冲的机制。值得注意的是对任务队列
进行操作时一定要进行加锁。
下面来详细解释一个线程池的创建实例:
第一部分为线程池管理器,负责线程的创建和工作队列当中任务的添加,代码如下:
template<typename T> class threadpool{ public: threadpool(int thread_number,int max_requests=10000); ~threadpool(); //往队列里面添加任务 bool append(T* request); private: static void* worker(void* arg);//工作线程运行的函数,不断从队列当中取出任务,并执行该任务 void run(); private: int m_thread_number;//线程池里面的线程数目 int m_max_requests;//请求队列当中允许的最大请求数 pthread_t* m_threads;//描述线程池的数组 std::list<T*> m_workqueue;//请求队列 locker m_queuelocker;//保护请求队列的互斥锁 sem m_queuestat;//当前是否有任务需要处理 bool m_stop;//是否结束当前的线程 };
以上的thread_number用于初始化该线程池创建的线程数,max_requests用来管理该线程池所能接受的最大任务数。
将其创建为模板类,方便该线程池能够处理各种任务。其中用locker来保护任务队列,该locker里面封装的是pthread_mu
tex_t,sem里面封装的是sem_t用来体现任务对了里面的任务数目,并且用于线程之间使用竞争的方式来取得任务。
该class的构造函数如下:
template<typename T> threadpool<T>::threadpool(int thread_number,int max_requests):m_thread_number(thread_number),m_max_requests(max_requests), m_threads(NULL),m_stop(false) { if(thread_number)<1||max_requests<1) throw std::exception(); //创建存储线程号的数组 m_threads = new pthread_t[m_thread_number]; if(!m_threads) throw std::exception(); //创建规定个数的线程,并将线程设置为detach() for(int i=0;i<thread_number;i++) { printf("create the %dth thread\n",i); if(pthread_create(m_threads+i,NULL,worker,this)!=0) { delete []m_threads; throw std::exception(); } if(pthread_detach(m_threads[i])) { //分离成功的话,则返回值为0 delete []m_threads; throw std::exception; } } }
在c++里面使用pthread_create()函数时,传入的第三个参数务必要是静态函数,本次的构造函数将
线程池对象本身作为参数传递给了工作线程。其作为第二部分的代码如下:
template<typename T> void* threadpool<T>::worker(void* arg){ //工作线程的参数为空指针的类型 threadpool* pool=(threadpool*)arg; pool->run(); return pool; } //工作线程执行的函数 template<typename T> void threadpool<T>::run() { //m_stop全局对象用来保证,当线程执行完一个任务队列当中的任务之后仍然能够继续从 while(!m_stop) { //等待当前的对立面有任务 m_queuestat.wait(); //加锁后读取并执行队列里面的任务 m_queuelocker.lock(); if(m_workqueue.empty()){ m_queuelocker.unlock(); continue; } T* request=m_workqueue.front(); m_workqueue.pop_front(); m_queuelocker.unlock(); if(!request) continue; request->process(); } }
工作线程,从任务队列当中取出任务,并执行。全局变量m_stop保证了工作线程在对象销毁
之前会一直不断的从任务队列当中取出任务并执行。
本次的线程池没有针对具体的任务形式,因此没有涉及任务接口的涉及,等以后补充。
原文地址:https://www.cnblogs.com/wangkaia/p/11952990.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 限流算法简介及Guava RateLimiter令牌桶限流介绍
- K8S的名称空间创建&&版本的升级、回滚操作
- SAP Cloud for Customer CLR(Code List Restriction)的一种高级用法
- SAP WebClient UI One Hit Navigation的实现方法
- 【打包构建】Mac下使用expect实现执行sudo命令时自动输入密码
- ASP.NET Core 奇淫技巧之SPA部署
- SAP Cloud for Customer Rule Editor的使用方法和底层工作原理
- (数据科学学习手札94)QGIS+Conda+jupyter玩转Python GIS
- 72-STM32+ESP8266+AIR202基本控制篇-移植使用-移植Android的MQTT包到自己的工程项目
- 用上Latex实现编辑伪代码
- TensorFlow交叉熵函数(cross_entropy)·理解
- 第05期:Prometheus 数据查询(一)
- 技术分享 | MySQL 复制那点事 - Seconds_behind_Master 参数调查笔记
- 线程有多少种状态?Runnable 一定在执行任务吗?
- swift 中类(class)和结构体(struct)区别