当前位置: 首页 > news >正文

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;
}


 

相关文章:

C++ 线程池

目录 一、线程池实现原理 二、定义线程池的结构 三、创建线程池实例 四、添加工作的线程的任务函数 五、管理者线程的任务函数 六、往线程池中添加任务 七、获取线程池工作的线程数量与活着的线程数量 八、线程池的销毁 一、线程池实现原理 线程池的组成主要分为3个部…...

测试框架pytest教程(6)钩子函数hook开发pytest插件

pytest hook 函数也叫钩子函数&#xff0c;pytest 提供了大量的钩子函数&#xff0c;可以在用例的不同生命周期自动调用。 比如&#xff0c;在测试用例收集阶段&#xff0c;可利用 hook 函数修改测试用例名称的编码。 pytest的hook是基于Python的插件系统实现的&#xff0c;使…...

【Rust】Rust学习 第十七章Rust 的面向对象特性

面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是一种模式化编程方式。对象&#xff08;Object&#xff09;来源于 20 世纪 60 年代的 Simula 编程语言。这些对象影响了 Alan Kay 的编程架构中对象之间的消息传递。他在 1967 年创造了 面向对…...

Redis系列(四):哨兵机制详解

首发博客地址 https://blog.zysicyj.top/ 前面我们说过&#xff0c;redis采用了读写分离的方式实现高可靠。后面我们说了&#xff0c;为了防止主节点压力过大&#xff0c;优化成了主-从-从模式 思考一个问题&#xff0c;主节点此时挂了怎么办 这里主从模式下涉及到的几个问题&a…...

一个滚动框高度动态计算解决方案

需求描述&#xff0c;一个嵌套了很多层div或者其他标签的内容框&#xff0c;而它的外层没有设置高度&#xff0c;或者使用百分比&#xff0c;而本容器需要设置高度来实现滚动&#xff0c;要么写死px高度&#xff0c;但是不能自适应&#xff0c;此时需要一个直系父容器&#xff…...

Android瀑布流

以下是一个简单的示例代码&#xff0c;演示如何在Android Studio中解析指定网页的图片URL&#xff0c;并展示在错乱瀑布流布局中&#xff1a; 1. 添加网络权限&#xff1a;在项目的AndroidManifest.xml文件中添加以下权限&#xff1a; <uses-permission android:name"…...

Ubuntu搭建CT_ICP里程计的环境暨CT-ICP部署

CT-ICP部署以及运行复现过程 0.下载资源&#xff0c;并按照github原网址的过程进行。1.查看所需要的各个部分的版本。2.安装clang编译器3.进行超级构建3.1标准进行3.2构建过程中遇到的问题 4.构建并安装CT-ICP库4.1标准进行4.2遇到的问题及解决办法 5.构建 CT-ICP 的 ROS 包装5…...

微信小程序全局事件订阅eventBus

微信小程序全局事件订阅 在Vue开发中&#xff0c;我们可能用过eventBus来解决全局范围内的事件订阅及触发逻辑&#xff0c;在微信小程序的开发中我们可能也也会遇到同样的需求&#xff0c;那么我们尝试下在小程序&#xff08;原生小程序开发&#xff09;中实现类似eventBus的事…...

华为云cce发布若依前后分离版:2.nginx镜像操作

下载nginx docker的官方镜像。 docker资源很难找,我在我的空间上传了一个,需要的话可以下载: https://download.csdn.net/download/axe6404/88225311 下载后,请用以下方法安装 2.1 导入docker 官方nginx镜像。 将镜像包nginx docker镜像包nginx-dockerimage.tar放…...

TCP协议报文结构

TCP是什么 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、全双工的传输协议。它使用头部&#xff08;Header&#xff09;和数据&#xff08;Data&#xff09;来组织数据包&#xff0c;确保数据的可靠传输和按序传递。 TCP协议报文结构 下面详细阐述TCP…...

Day14-2-NodeJS后端开发流程

Day14-NodeJS后端工程化流程 一 apifox工具 apifox是目前最好的接口调试工具 1 环境搭建 安装登录创建项目接口里面创建对应文件夹在指定的文件夹里面创建接口2 GET请求 1 apifox发送GET请求 2 后端接收GET请求 router.get("/getUserinfo"...

计算机竞赛 基于CNN实现谣言检测 - python 深度学习 机器学习

文章目录 1 前言1.1 背景 2 数据集3 实现过程4 CNN网络实现5 模型训练部分6 模型评估7 预测结果8 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于CNN实现谣言检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&am…...

框架(Git基础详解及Git在idea中集成步骤)

目录 基础&#xff1a; idea集成Git并添加项目到git仓库 1.idea集成git&#xff0c;集成.git.exe文件 2.初始化本地Git仓库项目 3. 将工作区代码添加到暂存区 4.将暂存区代码添加到本地仓库 5.Git本地库操作 Idea集成Gitee并提交代码到第三方库 1.setting里搜索gitee 2.添…...

0基础学习VR全景平台篇 第88篇:智慧眼-成员管理

一、功能说明 成员管理&#xff0c;是指管理智慧眼项目的成员&#xff0c;拥有相关权限的人可以进行添加成员、分配成员角色、设置成员分类、修改成员以及删除成员五项操作。但是仅限于管理自己的下级成员&#xff0c;上级成员无权管理。 二、前台操作页面 登录智慧眼后台操…...

DSO 系列文章(2)——DSO点帧管理策略

文章目录 1.点所构成的残差Residual的管理1.1.前端残差的状态1.2.后端点的残差的状态1.3.点的某个残差的删除 2.点Point的管理2.1.如何删除点——点Point的删除2.2.边缘化时删除哪些点&#xff1f; 3.帧FrameHessian的管理 DSO代码注释&#xff1a;https://github.com/Cc19245/…...

无需公网IP——搭建web站点

文章目录 概述使用 Raspberry Pi Imager 安装 Raspberry Pi OS设置 Apache Web 服务器测试 web 站点安装静态样例站点将web站点发布到公网安装 Cpolar内网穿透cpolar进行token认证生成cpolar随机域名网址生成cpolar二级子域名将参数保存到cpolar配置文件中测试修改后配置文件配…...

swift 项目集成友盟推送

1, 需要用桥接文件 , 不然引用不到依赖库 2, 可以用测试模式测试, 可以debug 3, 测试模式获取deviceToken, 添加测试设备 deviceToken获取方法 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { le…...

Unity之用Transform 数组加多个空物体-->简单地控制物体按照指定路线自动行驶

文章目录 **原理解释**&#xff1a;**带注释的代码**&#xff1a;实际运用 当你需要实现物体按照指定路线行驶时&#xff0c;你可以通过以下步骤来实现&#xff1a; 原理解释&#xff1a; 路径点&#xff1a;你需要定义一系列路径点&#xff0c;这些点将构成物体行驶的路线。每…...

交换机生成树STP

生成树协议&#xff08;spanning-tree-protocol,stp&#xff09;&#xff1a;在具有物理环路的交换机网络上生成没有回路的逻辑网络的方法&#xff0c;生成树协议使用生成树算法&#xff0c;在一个具有冗余路径的容错网络中计算出一个无环路的路径&#xff0c;使一部分端口处于…...

3.微服务概述

1.大型网络架构变迁 SOA与微服务最大的差别就是服务拆分的细度&#xff0c;目前大多数微服务实际上是SOA架构&#xff0c;真正的微服务应该是一个接口对应一个服务器&#xff0c;开发速度快、成本高&#xff1b; 微服务SOA能拆分的就拆分是整体的&#xff0c;服务能放一起的都…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...