C++ 线程池

目录

一、线程池实现原理

二、定义线程池的结构

三、创建线程池实例

四、添加工作的线程的任务函数

五、管理者线程的任务函数

六、往线程池中添加任务

七、获取线程池工作的线程数量与活着的线程数量

八、线程池的销毁


一、线程池实现原理

线程池的组成主要分为3个部分。这三部分配合工作就可以得到一个完整的线程池:

1、任务队列,存储需要处理的任务。由工作的想程来处理这些任务

  • 通过线程池提供的API函数,将一个待处理的任务添加到任务队列,或者从任务队列中删除
  • 已处理的任务会被从任务队列中删除
  • 线程池的使用者,也就是调用线程池函数往任务队列中添加任务的线程就是生产者线程

2、工作的线程 (任务队列任务的消费者),N个

  • 线程池中维护了一定数量的工作线程,他们的作用是不停的读任务队列,从里边取出任务并处理
  • 工作的线程相当于是任务队列的消费者角色
  • 如果任务队列为空,工作的线程将会被阻塞(使用条件变量/信号量阻塞)
  • 如果阻塞之后有了新的任务,由生产者将阻塞解除,工作线程开始工作

3、管理者线程(不处理任务队列中的任务),1个

  • 它的任务是周期性的对任务队列中的任务数量以及处于忙状态的工作线程个数进行检测

          ——当任务过多的时候,可以适当的创建一些新的工作线程

          ——当任务过少的时候,可以适当的销毁一些工作的线程

二、定义线程池的结构

#include "threadpool.h"//任务结构体
typedef struct Task
{void (*function) (void* arg);void* arg;
}Task;//线程池结构体
struct ThreadPool
{//任务队列Task* taskQ;int queueCapacity;     //容量int queueSize;         //当前任务个数int queueFront;        //队头->取数据int queueRear;         //队尾->放数据pthread_t managerID;   //管理者线程IDpthread_t *threadIDs;  //工作的线程IDint minNum;            //最小线程数量int maxNum;            //最大线程数量int busyNum;           //忙的线程的个数int liveNum;           //存活的线程的个数int exitNum;           //要销毁的线程个数pthread _mutex_t mutexPool;       //锁整个的线程池pthread_mutex_t mutexBusy;        //锁busyNum变量            pthread_cond_t notFull;           //任务队列是不是满了pthread_cond_t notEmpty;          //任务队列是不是空了int shutdown;               //是不是要销毁线程池,销毁为1,不销毁为0
};

三、创建线程池实例

typedef struct ThreadPool ThreadPool;
ThreadPool* threadPoolCreate(int min, int max, int queueSize)
{ThreadPool* pool=(ThreadPool*)malloc(sizeof (ThreadPool));do{if (pool == NULL){printf ( "malloc threadpool fail ... \n");break;}pool->threadIDs = (pthread_t *) malloc(sizeof(pthread_t) *max);if(pool->threadIDs == NULL){printf ("malloc threadIDs fail ... \n");break;}memset(pool->threadIDs,0, sizeof (pthread_t) * max);pool->minNum = min;pool->maxNum = max;pool->busyNum = 0;pool->liveNum = min; //和最小个数相等pool->exitNum = 0;if (pt.hread _mutex_init ( &pool->mutexPool,NUTI) !=0 ||pthread_mutex_init ( &pool->mutexBusy,NULL) !=0 ||pthread_cond_init (&pool->notEmpty,NULL) !=0 ||pthread_cond_init ( &pool->notFull,NULL) !=0 ){    printf ( "mutex or condition init fail ...\n");break;}//任务队列pool->taskQ = malloc(sizeof (Task) * queueSize);pool->queueCapacity =qucuesizo;pool->queueSize= 0;pool->queueFront =0;pool->queueRear = 0;pool->shutdown = 0;//创建线程pthread_create ( &pool->managerID,NULL,manager,NULL);for (int i = 0; i < min; ++i){pthread create (&pool->threadIDs[i],NULL,worker,NULL);}}whiie (O);//释放资源if(pool && pool->threadIDs) free(pool->threadIDs);if(pool && pool->taskQ) free(pool->taskQ);if(pool) free(pool);return NULL;
}

四、添加工作的线程的任务函数

void* worker (void* arg)
{ThreadPool* pool = (ThreadPool*)arg;while (1){pthread_ mutex_lock(&pool->mtexPool) ;!当前任务队列是否为空while (pool->queuesize == 0 && !pool->shutdown ){//阻塞工作线程pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);//判断是不是要销毁线程if (pool->exitNum > 0){pool->exitNum--;pthread_ mutex_unlock(&pool->mtexPool) ;!当前任务队列是否为空pthread_exit (NULL);}}//判断线程池是否被关闭了if (pool->shutdown ){pthread_mutex_unlock(&pool->mutexPool);pthread_exit(NULL);}//从任务队列中取出一个任务Task task;task.function = pool->taskQ[pool->queueFront].function;task.arg = pool->taskQ[pool->queueFront].arg;//移动头结点pool->queueFront =(pool->queueFront + 1) % pool->queueCapacity;pool->queuesize--;//解锁pthread_cond_signal(&pool->notFull);pthread_mutex_unlock(&pool->mutexPool);printf("thread %ld start working ...\n");pthread mutex_lock (&pool->mutexBusy);pool->busyNum++;pthread mutex_unlock (&pool->mutexBusy) ;task.function(task.arg) ; //或者 (*task.function) (task.arg) 进行调用;free(task.arg);task.arg=NULL;printf("thread %ld end working ...\n");pthread_mutex_lock (&pool->mutexBusy);pool->busyNum--;pthread mutex_unlock (&pool->mutexBusy) ;     }return NULL;
}

五、管理者线程的任务函数

const int NUMBER = 2;
void* manaqer(void* arg)
{ThreadPool* pool = (ThreadPool+)arg;while(!pool->shutdown){//每隔3s检测一次sleep(3);//取出线程池中任务的数量和当前线程的数量pthread_mutex_lock(&pool->muatexPool) ;int queueSize =pool->queuesize;int liveNum = pool->liveNum;pthread_mutex_unlock( &pool->mutexPool) ;//取出忙的线程的数量pthread_mutex_lock(&pool->mutexBusy);int busyNum = pool->busyNum;pthread_mutex__lock(&pool->mutexBusy) ;//添加线程// 任务的个数 > 存活的线程个数 && 存活的线程数 < 最大线程数if (queueSize > liveNum && liveNum< pool->maxNum){pthread_mutex_lock(&pool->mutexPool);int counter = 0;for (int i = 0; i < pool->maxNum && counter < NUMBER && pool->liveNum < pool->maxNum ; ++i){if (pool->threadIDs[i] == 0){pthread_create( &pool->threadIDs[i],NULI,worker, pool);counter++;pool->liveNum++;}}pthread_mutex_unlock(&pool->mutexPool);}// 销毁线程// 忙的线程*2 < 存活的线程数 && 存活的线程 > 最小线程数if(busyNum * 2< liveNum && liveNum > pool->minNum){pthread_mutex_lock(&pool->mutexPool);pool->exitNum = NUMBER;pthread_mutex_unlock(&pcol->mutexPool);// 让工作的线程自杀Ifor(int i=0;i<NUMBER; ++i){pthread_cond_signal(&pool->notEmpty);}}}
}

六、往线程池中添加任务

void threadPoolAdd(ThreadPool* pool,void (*func)(void*), void* arg)
{pthread_mutex_lock(&pool->mutexPool);while(pool->queueSize == pool->queueCapacity && !pool->shutdown){//阻塞生产者线程pthread_cond_wait( &pool->notFull,&pool->mutexPool) ;}if (pool->shutdown){pthread_mutex_unlock ( &pool->mutexPool) ;return;}//添加任务pool->taskQ[pool->queueRear].function = func;pool->taskQ[pool->queueRear].arg = arg;pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity;pool->queuesize++;pthread_cond_signal( &pool->notEmpty);pthread_mutex_unlock(&pool->mutexPool) ;
}

七、获取线程池工作的线程数量与活着的线程数量

//获取线程池中工作的线程数量
int threadPoolBusyNum ( ThreadPool* pool)
{pthread_mutex_lock(&pool->mutexBusy);int busyNum = pool->busyNum;pthread_mutex_unlock(&pool->mutexBusy);return busyNum;
}//获取线程池中活着的线程数量
int threadPoolAliveNum (ThreadPool*pool)
{pthread_mutex_lock(&pool->mutexPool);int busyNum = pool->liveNum;pthread_mutex_unlock(&pool->mutexPool);return aliveNum;
}

八、线程池的销毁

int threadPoolDestroy (ThreadPool* pool)
{if(pool == NULL){return -1;}//关闭线程池pool->shutdown = 1;//阻塞回收管理者线程pthread_join(pool->nanagerID,NULL);//唤醒阻塞的消费者线程for (int i = 0; i < pool->liveNum; ++i){pthread_cond_signal( &pool->notEmpty) ;}//释放堆内存if(pool->taskQ){free(pool->taskQ);pool->taskQ=NULL;}if(pool->threadIDs){free(pool->threadIDs);pool->threadIDs=NULL;}free(pool);pool=NULL;pthread_mutex_destroy( &pool->mutexPool);pthread_mutex_destroy( &pool->mutexBusy);pthread_cond_ destroy( &pool->notEmpty);pthread_cond_destroy ( &pool->notFull);return 0;
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/47221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入了解Git:介绍及常用命令指南

当今软件开发领域中&#xff0c;版本控制是一个至关重要的概念&#xff0c;而Git作为最流行的分布式版本控制系统&#xff0c;发挥着不可替代的作用。本文将介绍Git的基本概念以及常用命令&#xff0c;帮助你更好地理解和使用这一强大的工具。 Git简介 Git是一种分布式版本管…

从业务层的代码出发,去排查通用框架代码崩溃的问题

目录 1、问题说明 1.1、Release下崩溃&#xff0c;Debug下很难复现 1.2、用Windbg打开dump文件&#xff0c;发现崩溃在通用的框架代码中 2、进一步分析 2.1、使用IDA查看汇编代码尝试寻找崩溃的线索 2.2、在Windbg中查看相关变量的值 2.3、查看最近代码的修改记录&#…

代码随想录day11

20. 有效的括号 ● 力扣题目链接 ● 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串&#xff0c;判断字符串是否有效。 ● 有效字符串需满足&#xff1a; ● 左括号必须用相同类型的右括号闭合。 ● 左…

SAP ABAPG开发屏幕自动生成日期的搜索帮助

代码如下&#xff1a; REPORT z_jason_test_f4 . TABLES: s031. PARAMETER p_spmon TYPE spmon DEFAULT sy-datum0(6) OBLIGATORY. SELECT-OPTIONS s_spmon FOR s031-spmon DEFAULT sy-datum0(6) OBLIGATORY. AT SELECTION-SCREEN ON VALUE-REQUEST…

机器学习使用场景

在计算机系统中&#xff0c;“经验”通常以“数据”的形式存在。因此&#xff0c;机器学习的主要内容&#xff0c;是关于在计算机上从数据中产生Function的算法&#xff0c;这个Function的作用是将将输入映射成合理的输出。例如给Function输入猫的图片&#xff0c;Function能够…

Python面向对象植物大战僵尸

先来一波效果图 来看看如何设计游戏架构 import sysimport pygameclass BaseSprite(pygame.sprite.Sprite):def __init__(self, name):super().__init__()self.image pygame.image.load(name)self.rect self.image.get_rect()class AnimateSprite(BaseSprite):def __init__(…

C++信息学奥赛1131:基因相关性

这段代码的功能是比较两个字符串的相似度&#xff0c;并根据给定的阈值判断是否相似。 解析注释后的代码如下&#xff1a; #include <iostream> #include <string> using namespace std;int main() {double bf; // 定义双精度浮点数变量bf&#xff0c;用于存储阈…

机器学习深度学习——NLP实战(自然语言推断——数据集)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——NLP实战&#xff08;情感分析模型——textCNN实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器…

MAC钓鱼并Root权限上线CS并权限维持,以及所有的坑如何解决

本文转载于&#xff1a;https://www.freebuf.com/articles/web/350592.html 作者&#xff1a;文鸯涂鸦智能安全实验室 制作MAC 一、下载工具 首先从github上下载CrossC2。链接&#xff1a;https://github.com/gloxec/CrossC2/releases/tag/v3.1.0。 根据你CS客户端的操作系统选…

python 打印沁园春 雪 居中对齐 文本对齐

以下是python 中使用 DebugInfo 模块居中对齐打印《沁园春・雪》的效果 引入模块 pip install DebugInfopython代码 # -*- coding:UTF-8 -*-# region 引入必要依赖 from DebugInfo.DebugInfo import * # endregion诗文 沁园春 雪 作者: 毛主席 北国风光&#xff0c;千里冰封…

A Survey on Model Compression for Large Language Models

本文是LLM系列文章&#xff0c;关于模型压缩相关综述&#xff0c;针对《A Survey on Model Compression for Large Language Models》的翻译。 大模型的模型压缩综述 摘要1 引言2 方法3 度量和基准3.1 度量3.2 基准 4 挑战和未来方向5 结论 摘要 大型语言模型&#xff08;LLM…

Swagger2 使用

大家好 , 我是苏麟 , 今天带来Swagger的使用 . 官方文档 : 招摇文档 (swagger.io) 访问地址 : 在路径后加上doc.html 例如: http://localhost:8000/doc.html Swagger 使用 依赖 <!--Swagger依赖 核心--><dependency><groupId>io.springfox</groupId&g…

smartsofthelp 5.0 最专业的数据库优化工具,数据库配置优化,数据库高并发优化,SQL 语句优化...

下载地址:百度网盘 请输入提取码 SQL操作返回历史记录&#xff1a; 2023-08-21 20:42:08:220 输入&#xff1a;select version as 版本号 2023-08-21 20:42:08:223 输出&#xff1a;当前数据库实例版本号&#xff1a;Microsoft SQL Server 2012 - 11.0.2100.60 (X64) …

TheGem主题 - 创意多用途和高性能WooCommerce WordPress主题/网站

TheGem主题概述 – 适合所有人的TheGem 作为设计元素、样式和功能的终极 Web 构建工具箱而设计和开发&#xff0c;TheGem主题将帮助您在几分钟内构建一个令人印象深刻的高性能网站&#xff0c;而无需触及一行代码。不要在编码上浪费时间&#xff0c;探索你的创造力&#xff01…

docker优点简介和yum方式安装

一.docker简介 二.docker的优点 1.交付和部署速度快 2.高效虚拟化 3.迁移性和扩展性强 4.管理简单 三.docker的基本概念 1.镜像 2.容器 3.仓库 四.docker的安装部署 &#xff08;1&#xff09;点击容器 ​&#xff08;2&#xff09;选择docker-ce&#xff0c;根据相…

关于uniapp组件的坑

关于uniapp组件的坑 我有一个组件写的没什么问题,但是报下面这个错误 is not found in path “components/xxx/xxxx” (using by “components/yyy/yyy”) 最后经过排除发现命名需要驼峰命名法 我原本组件命名: 文件夹名 test_tttt 文件名 test_tttt.vue 不行 最后改成文件…

学习php中如何获取pdf文件中的文本内容

学习php中如何获取pdf文件中的文本内容 要使用PHP获取PDF文件中的文本内容&#xff0c;可以使用PDF解析库。以下是一些流行的PDF解析库&#xff1a; pdftotext&#xff1a;它是一个命令行工具&#xff0c;可以将PDF文件转换为文本文件。可以使用PHP exec()函数运行该工具。 FP…

【LVS】4、HAProxy搭建web集群

目前常见的Web集群调度器分为软件和硬件 软件通常使用开源的LVS、Haproxy、Nginx LVS性能最好&#xff08;基于内核转发&#xff09;&#xff0c;但是搭建相对复杂&#xff1b;Nginx的upstream模块支持群集功能&#xff0c;但是对群集节点健康检查功能不强&#xff0c;高并发性…

C# OpenCvSharp DNN 二维码增强 超分辨率

效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp; using OpenCvSharp.Dnn; using OpenCvSh…

eNSP综合小实验:VRRP、MSTP、Eth-Trunk、NAT、DHCP等技术应用

完成下图要求&#xff1a; 拓扑图&#xff1a; 配置命令&#xff1a; 由于交换机日志太多不便于复制&#xff0c;所以就复制命令。大概步骤如下&#xff1a; 第一步先分配IP地址&#xff0c;在sw1和sw2上创建VLAN100用于e0/0/3口配IP&#xff0c;在sw1、sw2、sw3、sw4上创建VL…