【线程池项目(三)】线程池CACHED模式的实现

news2025/1/18 21:11:49

在上一篇【线程池项目(二)】线程池FIXED模式的实现 中我们了解到到线程池fixed模式的大致实现原理,但对于一个比较完整的项目来说,我们还需要考虑到可能会发生的各种情况,比如用户提交的任务数可能在某一时刻急剧增加,而且每个任务的任务量比较小,在这种情况下,仅仅是在fixed模式下,可能会造成有些任务永远得不到执行或者等待非常久的时间,使用户体验变差。然,要是我们能够通过改良使能够执行任务的线程动态的创建和删除,那么就能很好的解决这个问题,也就是下面我们要介绍的cached模式下的线程池

由于第二篇中已经将线程池的关键技术点做了详细的介绍,而cached模式也是在fixed模式的基础上扩展而来的,所以对于下面的代码剖析仅仅关注于cached模式下的扩展部分

如果需要与本篇博客完全匹配的实现代码,也可以在 我的gitee 上下载对应的源码

项目经历——基于C++新特性以及模板编程实现的线程池

    • 一、cached模式设计的实现🧐🧐🧐
    • 二、重点理解 ThreadPool::~ThreadPool()析构函数😮😮😮
    • 三、思考 :thinking::thinking::thinking:
    • 四、总结😩😩😩

一、cached模式设计的实现🧐🧐🧐

这里需要提一句,既然在cached模式下,我们涉及到线程的动态创建和删除,那么肯定也需要考虑到,当所有任务执行完后,对于空闲线程的资源回收问题,毕竟咱们的CPU资源有限。

🙉 ThreadPool:private
之前fixed模式下,我们使用的是线程列表vector(非线程安全),这里需要回收指定线程的话,需要将其换成unordered_map<int, std::unique_ptr<Thread>>,把每个线程对象都与一个线程ID对应起来方便管理,而线程ID的话是由Thread里的静态变量generateId_自己生成的,见下图二:
在这里插入图片描述
在这里插入图片描述


🙈 ThreadPool::start() / ThreadPool::submitTask():
为了使每个线程对象都能够对应一个线程ID,不管是在刚开启线程池创建初始线程数时,还是在任务过多需要动态创建线程时,都需要在使用绑定器时预留一个参数占位符,供线程创建使用、线程回收时删除:
在这里插入图片描述
在这里插入图片描述


二、重点理解 ThreadPool::~ThreadPool()析构函数😮😮😮

🙊 线程池的析构函数这里很关键,通过设置线程池的运行状态,通知等待线程继续往下执行,用条件变量阻塞等待其他线程,判断其是否都已经结束
在这里插入图片描述
建议联系下面给出的线程函数方法的完整代码和测试程序认真理解,分析各种抢锁的情况,以及可能出现的问题,或者直接看我的博客【手写线程池(四)】项目死锁问题的分析



🥹 ThreadPool::threadFunc():
对于线程回收机制,我们规定了两个条件

  • fixed模式下,任务队列为空,无限期阻塞,不回收
  • cached模式下,任务队列为空,每次等待1s,轮询至60s,若还是没有任务到来,则回收该线程

对于时间,我们使用C++11标准里边的

  • std::chrono::high_resolution_clock().now()来获取、
  • std::chrono::duration_cast<std::chrono::seconds>(now - lastTime).count()来记录时间差

下面来贴一段完整的实现线程函数的代码截图:
在这里插入图片描述
在这里插入图片描述

这里我再给一段测试程序代码截图
在这里插入图片描述

三、思考 🤔🤔🤔

我们知道线程不外乎就两种状态,

  • 一种是wait状态,等待任务的到来,
  • 另一种是exec()状态,正在执行任务,还未执行完

根据以上三段完整代码,我们是否可以提出几个问题???

  • 用于执行任务的线程处于wait状态,主线程执行线程池的析构函数,会发生什么
  • 用于执行任务的线程处于exec()状态,主线程执行线程池的析构函数,会发生什么

其实还有第三种状态!!!

  • 当主线程准备执行析构函数把isPoolRunning置为false前,正在执行任务的线程恰好执行完任务并且再一次通过while(isPoolRunning)进入循环,会发生什么

这三个问题将在下一篇进行剖析,感兴趣的朋友可以先试着分析一下

四、总结😩😩😩

以上就是有关于【线程池项目(三)】线程池CACHED模式的实现 的内容,下一篇【线程池项目(四)】项目死锁问题的分析 将带大家剖析两个经典的死锁问题🔚🔚🔚

🌻🌻🌻如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏🌻🌻🌻

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

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

相关文章

5.2 Ajax 数据爬取实战

目录 1. 实战内容 2、Ajax 分析 3、爬取内容 4、存入MySQL 数据库 4.1 创建相关表 4.2 数据插入表中 5、总代码与结果 1. 实战内容 爬取Scrape | Movie的所有电影详情页的电影名、类别、时长、上映地及时间、简介、评分&#xff0c;并将这些内容存入MySQL数据库中。 2、…

在springboot中调用openai Api并实现流式响应

之前在《在springboot项目中调用openai API及我遇到的问题》这篇博客中&#xff0c;我实现了在springboot中调用openai接口&#xff0c;但是在这里的返回的信息是一次性全部返回的&#xff0c;如果返回的文字比较多&#xff0c;我们可能需要等很久。 所以需要考虑将请求接口响应…

LeetCode--代码详解 235.二叉搜索树得最近公共祖先

235.二叉搜索树得最近公共祖先 题目 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可…

【架构】面向人工智能 (AI) 的硬件的可靠性(2021)

由于激进的技术扩展&#xff0c;现代系统越来越容易受到可靠性威胁的影响&#xff0c;例如软错误、老化和工艺变化。这些威胁在硬件级别表现为位翻转&#xff0c;并且根据位置&#xff0c;可能会损坏输出&#xff0c;从而导致不准确或潜在的灾难性结果。 传统的缓解技术基于冗…

计算机网络Day03--物理层

信道复用技术 频分复用 时分复用 统计时分复用 频分复用&#xff08;FDM&#xff09; 最基本 将整个宽带分为多份&#xff0c;用户在分配到一定的频带后&#xff0c;在通信过程中自始至终都使用这个频带 所有的用户在同一时间占用不同的带宽资源&#xff0c;以并行的方式工…

一文带你彻底搞懂 Python 编程进阶之闭包

什么是闭包&#xff1a;在函数嵌套的情况下&#xff0c;内部的函数使用外部函数中的变量&#xff0c;并且外部函数返回了内部函数&#xff0c;我们将这个内部函数称之为闭包。 闭包是实现装饰器的基础&#xff0c;通过装饰器可以在不修改原函数代码的情况下增强其功能。 在Py…

JDK10新特性:探索Java10的编程新境界

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

nodejs+vue+ElementUi废品废弃资源回收系统

系统主要是以后台管理员管理为主。管理员需要先登录系统然后才可以使用本系统&#xff0c;管理员可以对系统用户管理、用户信息管理、回收站点管理、站点分类管理、站点分类管理、留言板管理、系统管理进行添加、查询、修改、删除&#xff0c;以保障废弃资源回收系统系统的正常…

异步框架Celery在Django中的运用

参考博客&#xff1a;https://www.cnblogs.com/pyedu/p/12461819.html 参考视频&#xff1a;01 celery的工作机制_哔哩哔哩_bilibili 定义&#xff1a;简单灵活、处理大量消息的分布式系统&#xff0c;专注于实时处理异步队列&#xff0c;支持任务调度 主要架构&#xff1a; …

YOLOv7基础 | 第2种方式:简化网络结构之yolov7.yaml(由104层简化为30层)

前言:Hello大家好,我是小哥谈。通过下载YOLOv7源码可知,原始的yolov7.yaml文件是拆开写的,比较混乱,也不好理解,并且为后续改进增添了很多困难。基于此种情况,笔者就给大家介绍一种将yolov7.yaml文件简化的方法,将104层简化为30层,并且参数量和计算量和原来是一致的,…

RK3568平台开发系列讲解(Linux系统篇)字符设备驱动:分配和注册字符设备

🚀返回专栏总目录 文章目录 一、分配和注册字符设备二、file_operations沉淀、分享、成长,让自己和他人都能有所收获!😄 一、分配和注册字符设备 字符设备在内核中表示为struct cdev的实例。在编写字符设备驱动程序时,目标是最终创建并注册与struct file_operations关联…

线程池的常用实现及执行流程

线程池 线程池线程池接口线程池参数线程池分类动态数目线程池固定数目线程池单例线程池任务调度线程池 线程池的执行流程 线程池 线程池接口 线程池参数 1、corePoolSize&#xff1a;核心线程数&#xff0c;线程池中最少线程&#xff0c;核心线程不会被回收。 2、maximumPoo…

Edting While Playing 瓦片地图编辑器开发整合导入自定义贴图 DEVC++ VS2022都可复制粘贴运行

接 多种类型图片模块读取-CSDN博客 与 Editing While Playing 使用 Easyx 开发的 RPG 地图编辑器 tilemap eaitor-CSDN博客 整合实现平面贴图纹理自定义 操作同上 导入步骤&#xff1a; 先运行程序&#xff0c;然后关闭&#xff0c;同目录下有四个文件夹&#xff0c; 把…

家政小程序有哪些功能 怎么制作

随着人们生活节奏的加快&#xff0c;家政服务变得越来越受到人们的青睐。为了提升家政服务的便捷性和高效性&#xff0c;家政小程序成为了越来越受欢迎的选择。下面具体介绍家政小程序有哪些功能&#xff0c;如何制作。 1. 展示家政服务 在小程序中&#xff0c;上传所有的家政…

Spring Cloud Alibaba - 利用Nacos实现高效动态线程池管理

文章目录 引言概述什么是动态线程池Nacos简介如何利用Nacos实现动态线程池管理应用场景Code版本说明POM配置文件Nacos Config配置文件加载顺序1. bootstrap.yml的加载2. application.yml的加载注意事项示例 nacos配置Data IdNacos中Data ID的命名格式解释${spring.application.…

力扣● 343. 整数拆分 ● 96.不同的二叉搜索树

● 343. 整数拆分 想不到&#xff0c;要勇于看题解。 关键在于理解递推公式。 1、DP数组及其下标的含义&#xff1a;dp[i]是分解i这个数得到的最大的乘积。 2、DP数组如何初始化&#xff1a;dp[0]和dp[1]都没意义&#xff0c;所以直接不赋值&#xff0c;初始化dp[2]1即可。…

maven 打包命令

Maven是基于项目对象模型(POM project object model)&#xff0c;可以通过一小段描述信息&#xff08;配置&#xff09;来管理项目的构建&#xff0c;报告和文档的软件项目管理工具。 Maven的核心功能便是合理叙述项目间的依赖关系&#xff0c;通俗点讲&#xff0c;就是通过po…

【openGL教程08】基于C++的着色器(02)

LearnOpenGL - Shaders 一、说明 着色器是openGL渲染的重要内容&#xff0c;客户如果想自我实现渲染灵活性&#xff0c;可以用着色器进行编程&#xff0c;这种程序小脚本被传送到GPU的显卡内部&#xff0c;起到动态灵活的着色作用。 二、着色器简述 正如“Hello Triangle”一章…

单片机05__串口USART通信__按键控制向上位机传输字符串

串口USART通信 通用UART介绍 1.通信的概念 计算机与外界进行信息交换的过程称之为通信。 在通信的过程中&#xff0c;通信双方都需要遵守的规则称之为通信协议。 硬件协议&#xff1a;将数据以什么样的方式传输过去 软件协议&#xff1a;将数据以什么样的顺序传输过去 2.常用…

C#与VisionPro联合开发——跳转页面

1、跳转页面并打开相机 From1 所有代码展示 using System; using System.IO; using System.Windows.Forms; //引入VisionPro命名空间 using Cognex.VisionPro;namespace ConnectCamera {public partial class Form1 : Form {public Form1() {InitializeComponent();}CogAcqFif…