线程池的实现v2.0(可伸缩线程池)

目录

前言

可伸缩线程池原理

可伸缩线程池实现

完整程序


前言

本篇可伸缩线程池的实现是在静态线程池上拓展而来,对于静态线程池的实现,请参考:

线程池的实现全过程v1.0版本(手把手创建,看完必掌握!!!)_竹烟淮雨的博客-CSDN博客

可伸缩线程池原理

对于静态线程池,我们额外引入一个管理线程专门来管理线程池。当线程池中的线程数量不足够匹配任务队列里的任务量,就增加线程;如果线程数量超出了任务队列的任务量,就减少线程。

具体可伸缩的条件由我们自己来规定,比如说待处理的任务数 > 正在工作的线程数*2,就增加线程;当前任务数*2 < 正在工作的线程数,就关闭一些线程。

可伸缩线程池实现

对之前V1.0版本的静态线程池进行修改,添加了一个名为management_thread的管理线程,该线程会根据任务队列的任务数量动态管理线程池中的线程数量。管理线程会在每次循环中根据一定的条件增加或减少线程数量,然后休眠一段时间后继续检查。这样就能根据任务负载自动调整线程池中的线程数量。

修改部分如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>struct job {void *(*func)(void *arg);void *arg;struct job *next;
};struct threadpool {int thread_num;pthread_t *pthread_ids;struct job *head;struct job *tail;int queue_max_num;int queue_cur_num;pthread_mutex_t mutex;pthread_cond_t queue_empty;pthread_cond_t queue_not_empty;pthread_cond_t queue_not_full;pthread_t management_thread; // 新增的管理线程
};void *threadpool_function(void *arg) {// 线程池工作线程的代码不变
}void *management_thread_function(void *arg) {struct threadpool *pool = (struct threadpool *)arg;while (1) {pthread_mutex_lock(&(pool->mutex));int active_threads = pool->queue_cur_num;int task_queue_size = pool->queue_cur_num;// 根据条件动态管理线程数量if (task_queue_size > 2 * active_threads && pool->thread_num < pool->queue_max_num) {int threads_to_add = (task_queue_size - active_threads + 1) / 2;for (int i = 0; i < threads_to_add; i++) {if (pool->thread_num < pool->queue_max_num) {pthread_create(&(pool->pthread_ids[pool->thread_num]), NULL, threadpool_function, (void *)pool);pool->thread_num++;}}} else if (2 * task_queue_size < active_threads && pool->thread_num > 1) {int threads_to_remove = (active_threads - 2 * task_queue_size + 1) / 2;for (int i = 0; i < threads_to_remove; i++) {if (pool->thread_num > 1) {pool->thread_num--;pthread_cancel(pool->pthread_ids[pool->thread_num]);pthread_join(pool->pthread_ids[pool->thread_num], NULL);}}}pthread_mutex_unlock(&(pool->mutex));sleep(1); // 等待一段时间后重新检查线程数量}
}struct threadpool *threadpool_init(int thread_num, int queue_max_num) {struct threadpool *pool = (struct threadpool *)malloc(sizeof(struct threadpool));// 初始化部分不变pthread_create(&(pool->management_thread), NULL, management_thread_function, (void *)pool);return pool;
}// 其他函数不变int main(int argc, char const *argv[]) {// 主函数部分不变
}

完整程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
struct job
{void *(*func)(void *arg);void *arg;struct job *next;
};struct threadpool
{int thread_num;         //已开启的线程数量pthread_t *pthread_ids; //保存线程池中线程的idstruct job *head;  //任务队列的头struct job *tail;  //任务队列的尾int queue_max_num; //任务队列的最大数int queue_cur_num; //任务队列已有多少个任务pthread_mutex_t mutex;pthread_cond_t queue_empty;     //控制任务队列为空的条件pthread_cond_t queue_not_empty; //控制任务队列不为空的条件pthread_cond_t queue_not_full;  //控制任务队列不为满的条件pthread_t management_thread; // 管理线程
};void *threadpool_function(void *arg)
{struct threadpool *pool = (struct threadpool *)arg;struct job *pjob = NULL;while (1){pthread_mutex_lock(&(pool->mutex));while (pool->queue_cur_num == 0){pthread_cond_wait(&(pool->queue_not_empty), &(pool->mutex));}pjob = pool->head;pool->queue_cur_num--;//对任务队列满队条件变量解阻塞if (pool->queue_cur_num != pool->queue_max_num){pthread_cond_broadcast(&(pool->queue_not_full));}if (pool->queue_cur_num == 0){pool->head = pool->tail = NULL;pthread_cond_broadcast(&(pool->queue_empty));}else{pool->head = pool->head->next;}pthread_mutex_unlock(&(pool->mutex));(*(pjob->func))(pjob->arg);free(pjob);pjob = NULL;}
}void *management_thread_function(void *arg)
{struct threadpool *pool = (struct threadpool *)arg;while (1){pthread_mutex_lock(&(pool->mutex));int active_threads = pool->queue_cur_num;  // 当前正在工作的线程数量int task_queue_size = pool->queue_cur_num; // 当前任务队列中的任务数量// 根据条件动态管理线程数量if (task_queue_size > 2 * active_threads && pool->thread_num < pool->queue_max_num){int threads_to_add = (task_queue_size - active_threads + 1) / 2;for (int i = 0; i < threads_to_add; i++){if (pool->thread_num < pool->queue_max_num){pthread_create(&(pool->pthread_ids[pool->thread_num]), NULL, threadpool_function, (void *)pool);pool->thread_num++;}}}else if (2 * task_queue_size < active_threads && pool->thread_num > 1){int threads_to_remove = (active_threads - 2 * task_queue_size + 1) / 2;for (int i = 0; i < threads_to_remove; i++){if (pool->thread_num > 1){pool->thread_num--;pthread_cancel(pool->pthread_ids[pool->thread_num]);pthread_join(pool->pthread_ids[pool->thread_num], NULL);}}}pthread_mutex_unlock(&(pool->mutex));sleep(1); // 等待一段时间后重新检查线程数量}
}struct threadpool *threadpool_init(int thread_num, int queue_max_num)
{struct threadpool *pool = (struct threadpool *)malloc(sizeof(struct threadpool));// mallocpool->queue_max_num = queue_max_num;pool->queue_cur_num = 0;pool->head = NULL;pool->tail = NULL;pthread_mutex_init(&(pool->mutex), NULL);pthread_cond_init(&(pool->queue_empty), NULL);pthread_cond_init(&(pool->queue_not_empty), NULL);pthread_cond_init(&(pool->queue_not_full), NULL);pool->thread_num = thread_num;pool->pthread_ids = malloc(sizeof(pthread_t) * thread_num);// mallocfor (int i = 0; i < pool->thread_num; i++){pthread_create(&(pool->pthread_ids[i]), NULL, threadpool_function, (void *)pool);}pthread_create(&(pool->management_thread), NULL, management_thread_function, (void *)pool);return pool;
}void threadpool_add_job(struct threadpool *pool, void *(*func)(void *arg), void *arg)
{pthread_mutex_lock(&(pool->mutex));//如果任务队列已满while (pool->queue_cur_num == pool->queue_max_num){pthread_cond_wait(&(pool->queue_not_full), &(pool->mutex));}struct job *pjob = (struct job *)malloc(sizeof(struct job));pjob->func = func;pjob->arg = arg;if (pool->head == NULL){pool->head = pool->tail = pjob;pthread_cond_broadcast(&(pool->queue_not_empty));}else{pool->tail->next = pjob;pool->tail = pjob;}pool->queue_cur_num++;pthread_mutex_unlock(&(pool->mutex));
}void thread_destroy(struct threadpool *pool)
{pthread_mutex_lock(&(pool->mutex));while (pool->queue_cur_num != 0){pthread_cond_wait(&(pool->queue_empty), &(pool->mutex));}pthread_mutex_unlock(&(pool->mutex));//通知所有阻塞的线程pthread_cond_broadcast(&(pool->queue_not_empty));pthread_cond_broadcast(&(pool->queue_not_full)); //可不要for (int i = 0; i < pool->thread_num; i++){printf("thread exit!\n");pthread_cancel(pool->pthread_ids[i]);pthread_join(pool->pthread_ids[i], NULL);}pthread_mutex_destroy(&(pool->mutex));pthread_cond_destroy(&(pool->queue_empty));pthread_cond_destroy(&(pool->queue_not_empty));pthread_cond_destroy(&(pool->queue_not_full));free(pool->pthread_ids);//为了以防万一,任务队列不为空,要对所有任务进行销毁struct job *temp;while (pool->head != NULL){temp = pool->head;pool->head = temp->next;free(temp);}free(pool);
}void *work(void *arg)
{char *p = (char *)arg;printf("hello world! %s\n", p);printf("welcome to Nanjing! %s\n", p);sleep(1);
}int main(int argc, char const *argv[])
{struct threadpool *pool = threadpool_init(10, 100);threadpool_add_job(pool, work, "1");threadpool_add_job(pool, work, "2");threadpool_add_job(pool, work, "3");threadpool_add_job(pool, work, "4");threadpool_add_job(pool, work, "5");threadpool_add_job(pool, work, "6");threadpool_add_job(pool, work, "7");threadpool_add_job(pool, work, "8");threadpool_add_job(pool, work, "9");threadpool_add_job(pool, work, "10");threadpool_add_job(pool, work, "11");threadpool_add_job(pool, work, "12");threadpool_add_job(pool, work, "13");threadpool_add_job(pool, work, "14");threadpool_add_job(pool, work, "15");threadpool_add_job(pool, work, "16");threadpool_add_job(pool, work, "17");threadpool_add_job(pool, work, "18");threadpool_add_job(pool, work, "19");threadpool_add_job(pool, work, "20");thread_destroy(pool);sleep(5);return 0;
}

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

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

相关文章

Java课题笔记~Element UI

Element&#xff1a;是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库&#xff0c;用于快速构建网页。 Element 提供了很多组件&#xff08;组成网页的部件&#xff09;供我们使用。例如 超链接、按钮、图片、表格等等~ 如下图左边的是我们编写页面看到的按钮&#…

5G与4G的RRC协议之异同

什么是无线资源控制&#xff08;RRC&#xff09;&#xff1f; 我们知道&#xff0c;在移动通信中&#xff0c;无线资源管理是非常重要的一个环节&#xff0c;首先介绍一下什么是无线资源控制&#xff08;RRC&#xff09;。 手机和网络通过无线信道相互通信&#xff0c;彼此交…

【踩坑日记】STM32 USART 串口与 FreeRTOS 冲突

文章目录 问题描述问题出现的环境问题解决过程第一步第二步第三步第四步第五步第六步第七步第八步 后续验证一些思考类似的问题后记 问题描述 笔者使用 FreeRTOS 创建了两个任务&#xff0c;使两颗 LED 以不同频率闪烁&#xff0c;但是在加入串口 USART 部分代码后&#xff0c…

Mysql 开窗函数(窗口函数)

文章目录 全部数据示例1&#xff08;说明&#xff09;开窗函数可以比groupby多查出条件列外的字段&#xff0c;开窗函数主要是为了跟聚合函数一起使用&#xff0c;达到分组统计效果&#xff0c;并且开窗函数的结果集基本都是跟总行数一样示例2示例3示例4错误示例1错误示例2错误…

Flink源码之Checkpoint执行流程

Checkpoint完整流程如上图所示&#xff1a; JobMaster的CheckpointCoordinator向所有SourceTask发送RPC触发一次CheckPointSourceTask向下游广播CheckpointBarrierSouceTask完成状态快照后向JobMaster发送快照结果非SouceTask在Barrier对齐后完成状态快照向JobMaster发送快照结…

LION AI 大模型落地,首搭星纪元 ES

自新能源汽车蓬勃发展以来&#xff0c;随着潮流不断进步和变革的“四大件”有着明显变化。其中有&#xff1a;平台、智能驾驶、配置、以及车机。方方面面都有着不同程度的革新。 而车机方面&#xff0c;从以前老旧的媒体机、 CD 机发展至如今具有拓展性、开放性、智能化的车机…

[保研/考研机试] KY207 二叉排序树 清华大学复试上机题 C++实现

题目链接&#xff1a; 二叉排序树_牛客题霸_牛客网二叉排序树&#xff0c;也称为二叉查找树。可以是一颗空树&#xff0c;也可以是一颗具有如下特性的非空二叉树&#xff1a; 1。题目来自【牛客题霸】https://www.nowcoder.com/share/jump/437195121692721757794 描述&#x…

滑动窗口介绍

1.基本概念 利用单调性&#xff0c;使用同向双指针&#xff0c;两个指针之间形成一个窗口 子串与子数组都是连续的一段子序列时不连续的 2.为什么可以用滑动窗口&#xff1f; 暴力解决时发现两个指针不需要回退&#xff08;没必要回退&#xff0c;一定不会符合结果&#xf…

【网络】数据链路层——MAC帧协议 | ARP协议

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 来到数据链路层后&#xff0c;完整的数据被叫做数据帧&#xff0c;习惯上称之为MAC帧。 MAC帧协议 | A…

jenkins全量迁移

文章目录 1、目的2、迁移1&#xff09;查看jenkins的主目录2&#xff09;登录要迁出的服务器打包3&#xff09;找到对应的war包4&#xff09;登录对应迁入服务&#xff0c;上传war包和打包的jenkins数据等5&#xff09;在新的服务器解压迁入的数据等&#xff0c;并查看端口是否…

# Lua与C++交互(二)———— 交互

C 调用lua 基础调用 再来温习一下 myName “beauty girl” C想要获取myName的值&#xff0c;根据规则&#xff0c;它需要把myName压入栈中&#xff0c;这样lua就能看到&#xff1b;lua从堆栈中获取myName的值&#xff0c;此时栈顶为空&#xff1b;lua拿着myName去全局表中查…

【Jenkins】rpm方式安装Jenkins(2.401,jdk版本17)

目录 【Jenkins】rpm方式安装Jenkins 1、主机初始化 2、软件要求 RPM包安装的内容 配置文件说明 3、web操作 【Jenkins】rpm方式安装Jenkins 1、主机初始化 [rootlocalhost ~]# hostname jenkins[rootlocalhost ~]# bash[rootjenkins ~]# systemctl stop firewalld[roo…

YOLOv8教程系列:三、K折交叉验证——让你的每一份标注数据都物尽其用(yolov8目标检测+k折交叉验证法)

YOLOv8教程系列&#xff1a;三、K折交叉验证——让你的每一份标注数据都物尽其用&#xff08;yolov8目标检测k折交叉验证法&#xff09; 0.引言 k折交叉验证&#xff08;K-Fold Cross-Validation&#xff09;是一种在机器学习中常用的模型评估技术&#xff0c;用于估计模型的性…

Java详解编译型和解释型语言

在计算机的高级编程语言类型分为两种&#xff0c;分别是编译型和解释型&#xff0c;而Java既有编译型又有解释型 什么是编译型&#xff1f;什么是解释型&#xff1f; 字面上来说编译和解释都有‘翻译’的意思&#xff0c;而她们两个的区别是‘翻译’的时机不同&#xff0c;什…

Python采集电商平台泳衣数据进行可视化分析

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: python 3.8 解释器 pycharm 编辑器 模块使用: 第三方模块 需要安装 requests —> 发送 HTTP请求 内置模块 不需要安装 csv —> 数据处理中经常会用到的一种文件格式 第三方模块安装&#xff1a…

实验五 Linux 内核的安装与加载

【实验目的】 掌握 uboot 的使用方法&#xff0c;能够使用 uboot 安装和加载内核 【实验环境】 ubuntu 14.04 发行版FS4412 实验平台 【注意事项】 实验步骤中以“$”开头的命令表示在 ubuntu 环境下执行&#xff0c;以“#”开头的命令表 示在开发板下执行 【实验步骤】 …

计算机视觉 -- 图像分割

文章目录 1. 图像分割2. FCN2.1 语义分割– FCN &#xff08;Fully Convolutional Networks&#xff09;2.2 FCN--deconv2.3 Unpool2.4 拓展–DeconvNet 3. 实例分割3.1 实例分割--Mask R-CNN3.2 Mask R-CNN3.3 Faster R-CNN与 Mask R-CNN3.4 Mask R-CNN&#xff1a;Resnet1013…

ES搭建集群

一、创建 elasticsearch-cluster 文件夹 创建 elasticsearch-7.8.0-cluster 文件夹&#xff0c;在内部复制三个 elasticsearch 服务。 然后每个文件目录中每个节点的 config/elasticsearch.yml 配置文件 node-1001 节点 #节点 1 的配置信息&#xff1a; #集群名称&#xff0…

【数据备份、恢复、迁移与容灾】上海道宁与云祺科技为企业用户提供云数据中心容灾备份解决方案

云祺容灾备份系统支持 主流虚拟化环境下的虚拟机备份 提供对云基础设施 云架构平台以及 应用系统的全方位数据保护 云祺容灾备份系统规范功能 增强决策能力 高效恢复数据至可用状态 有效降低恢复成本 更大限度减少业务中断时间 保障业务可访问性 开发商介绍 成都云祺…

LSTM数学计算公式

LSTM&#xff08;长短期记忆网络&#xff09;是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;常用于处理时间序列相关的任务。下面将简要介绍LSTM的数学推导和公式模型。 在训练一般神经网络模型时&#xff0c;通常用,其中W为权重&#xff0c;X为输入&#…