【线程池项目(二)】线程池FIXED模式的实现

在上一篇【线程池项目(一)】项目介绍和代码展示 中,我们展示了线程池的两个版本实现,它们的代码在具体的实现细节上是优化过了的。下文提供的代码并非完整,也有很多地方尚需改善,但这些差异对理解整个项目而言,影响并不会太大。因此,在接下来的讨论中,我们将重点放在对项目代码的理解上。

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

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

    • 一、设计思路
    • 二、关键技术点
      • (1)线程池类ThreadPool
      • (2)线程类Thread
      • (3)信号量类Semaphore
      • (4)上帝类Any
      • (5)任务抽象基类Task
      • (6)提交任务的返回值Result
    • 三、分析图例,理解函数执行过程
    • 四、总结

一、设计思路

使用C++ OOP面向对象编程的思想,设计了6个类:

  • ThreadPool: 负责线程池的创建ThreadPool();、开启start()、设置模式setMode(这里不需要,默认FIXED)、提交任务submitTask()、线程函数threadFunc()(至于为什么要把线程函数放入ThreadPool里,而不是在Thread里,后面会解释)
  • Thread: 负责线程的创建Thread(),定义了函数对象类型ThreadFunc
  • Task: 对外(即用户)提供一个抽象类接口,用户可以重写run()函数来提供相应任务
  • Any: 模仿C++17中的any,可以接收任意的类型
  • Result: 作为Any的依赖,接收task任务在用户提交完成后的返回值类型
  • Semaphore: 线程的通信机制,模仿C++20的Semaphore,用于通知用户提交的任务是否已经被相应的线程执行完毕

二、关键技术点

(1)线程池类ThreadPool

🤠开启线程池start():
当创建线程对象时,我们使用 std::bind()绑定器将线程池的成员方法 threadFunc与当前线程池的 this 指针绑定到一起,作为创建线程对象的一个参数,传递给 std::thread 线程对象。这样,在 Thread 类的成员方法中,就可以直接通过调用 ThreadPool 的线程函数 threadFunc 来访问线程池中的成员变量和方法。通过这种绑定方式,也可以解决变参的问题,因为所有相关的参数都已经被绑定到这个线程函数上。因此,我们可以使用别名 using ThreadFunc = std::function<void()> 来定义线程函数的类型。
在这里插入图片描述


🥳提交任务submitTask():
使用互斥锁unique_lock()来维护线程安全,结合条件变量notFull的使用,判断1s内,任务队列中任务的数目是否已达上限,若已达,则阻塞返回提交失败,反之入队,通知其余线程任务队列中有任务能够执行了,返回提交成功任务的返回值Result(sp, true(default)),关于Result见下文
在这里插入图片描述


🥸线程函数threadFunc():
由于线程函数需要获取任务队列里的任务,在获取任务的同时需要线程池中互斥锁和条件变量的管理,直接定义在Thread里不好进行相关操作,定义在全局中也不好访问私有的成员变量,所以把它放在ThreadPool里实现,但是我们的目的是让线程通过线程函数来执行任务,所以我们定义相应的Thread构造函数把ThreadPool的线程函数threadFunc给到Thread,用Thread类的成员变量func_来存储。代码同上,就不赘述了
在这里插入图片描述

(2)线程类Thread

😎 这里没什么可说的,就是一个分离线程detach,延长线程函数的生命周期至主线程结束(即创建线程池的线程)
在这里插入图片描述

(3)信号量类Semaphore

🤓 模拟C++20的semaphore,用waitpost分别申请和释放信号量资源来控制用户提交的任务是否被执行完毕
在这里插入图片描述

(4)上帝类Any

🧐 考虑到用户提交任务时,可能不仅仅需要把任务处理完成,还可能需要得到任务处理完成后的返回值,所以我们设计了一个Any类作为接收任意类型的返回值,即让一个类型可以指向其他的任意类型。然我们知道,基类指针可以执行派生类对象,根据data(存储用户返回的数据,用模板实现)构造出一个派生类对象,这时候我们就可以使用Any里的基类指针指向它,并通过向下转型取出data。这里需要理解一下Any的构造函数,编译器在用户提交的任务执行完返回时是如何处理的
在这里插入图片描述

(5)任务抽象基类Task

😯 由于TaskResult是有耦合的,Result里用智能指针shared_ptr定义的Task类型的成员变量task_,为了避免发生智能指针的交叉引用问题,Task里使用了裸指针定义Result类型的result_,指向用户提交任务后返回的Result,其生命周期 > task, 通过result_Task里面调用Result里的成员方法,来控制Any返回值的获取,在exec()中发生多态调用(run()在基类中为纯虚函数,供用户重写)
在这里插入图片描述

(6)提交任务的返回值Result

😳 构造函数Result(…):
判断提交任务是否成功,并把当前对象this给到成员变量task_里,供Task类中的相关方法使用,如上
在这里插入图片描述


🥹 获取返回值Any ,setVal()、get():
通过信号量的waitpost操作和资源转移std::move()来进行
在这里插入图片描述

三、分析图例,理解函数执行过程

在这里插入图片描述

四、总结

以上就是有关于【线程池项目(二)】线程池FIXED模式的实现的内容,下一篇【线程池项目(三)】介绍线程池fixed模式的具体实现过程🔚🔚🔚

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

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

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

相关文章

靡语IT:JavaScript数组

目录 1.数组&#xff1a;Array 2.Array.length 3.数组的声明(创建)方法 4.数组去重 5.数组遍历 6.类数组对象 1.数组&#xff1a;Array 数组对象的作用是&#xff1a;使用单独的变量名来存储一系列的值。 参数 参数 size 是期望的数组元素个数。返回的数组&#xff0…

操作系统(1)——学习导论(Ⅰ)

目录 小程一言专栏链接: [link](http://t.csdnimg.cn/6grrU) 学习导论什么是操作系统主要功能强调 操作系统历史硬件层面处理器重要特点and功能 存储器磁盘I/O设备小程常用的I/O设备及其特点 小程一言 本操作系统专栏&#xff0c;是小程在学操作系统的过程中的第一步&#xff…

200万上下文窗口创飞Gemini 1.5!微软来砸谷歌场子了

谷歌刚刷新大模型上下文窗口长度记录&#xff0c;发布支持100万token的Gemini 1.5&#xff0c;微软就来砸场子了。 推出大模型上下文窗口拉长新方法——LongRoPE&#xff0c;一口气将上下文拉至2048k token&#xff0c;也就是200多万&#xff01; 并且1000步微调内&#xff0c…

【刷题记录】链表的回文结构

本系列博客为个人刷题思路分享&#xff0c;有需要借鉴即可。 1.题目链接&#xff1a; LINK 2.详解思路&#xff1a; 思路&#xff1a;思路&#xff1a;先找到中间节点&#xff0c;然后逆置后半部分链表&#xff0c;一个指针指向链表的头节点&#xff0c;再一个指针指向逆置的头…

ELK介绍以及搭建

基础环境 hostnamectl set-hostname els01 hostnamectl set-hostname els02 hostnamectl set-hostname els03 hostnamectl set-hostname kbased -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config systemctl stop firewalld & systemctl disable firewalld# 安…

c语言的数据结构:找环状链表入口处

一起<(&#xffe3;︶&#xffe3;)↗[GO!] 1.如何判断一个链表是否有环 思路:设定两个快慢指针fast和slow,fast每次走两个结点,slow每次走一个节点 如果fast指针遇到了Null,那么这个链表没有环,如果fast和slow可以相遇,则代表这个链表有环 代码如下 N:fast先进环,slow后…

鼠标右键助手专业版 MouseBoost PRO for Mac v3.3.6中文破解

MouseBoost Pro mac版是一款简单实用的鼠标右键助手专业版&#xff0c;MouseBoost Pro for Mac只要轻点你的鼠标右键&#xff0c;就可以激活你想要的各种功能&#xff0c;让你的工作效率大幅度提高&#xff0c;非常好用。 软件下载&#xff1a;MouseBoost PRO for Mac v3.3.6中…

leet hot 100-2 字母异位词分组

字母异位词分组 原题链接思路代码 原题链接 leet hot 100-2 49. 字母异位词分组 思路 要求把含有相同字母的放到一起&#xff0c;我们可以遍历每一个字符串 将他们重新排序&#xff0c;将排序完是一样的字符串放在一起 用无序容器存放起来 然后遍历这个无序map容器将排序后相…

解决数学计算公式在前端项目里的展示,涉及换肤适配各个框架

有时候我们项目里面会嵌套一些数学公式说明 例如 可能你会发现市面上有很多的第三方库可以实现&#xff0c;比如&#xff1a; MathJax&#xff1a; https://www.mathjax.org/ 但是我们项目里面用到公式可能就一个页面&#xff0c;引一个第三方库进来会显得十分臃肿&#xff0…

JavaScript原型继承与面向对象编程思想

原型继承与面向对象编程思想 在JavaScript中&#xff0c;原型(prototype)、构造函数(constructor)和实例对象(instance)是面向对象编程中的重要概念&#xff0c;并且它们之间存在着紧密的关系。 原型(prototype)&#xff1a;原型是JavaScript中对象之间关联的一种机制。每个Ja…

c++笔记理解

1.封装 &#xff08;1&#xff09;构造函数不是必须在的 可以通过行为修改属性 &#xff08;2&#xff09;private和protected区别在于继承那里要学 &#xff08;3&#xff09;类默认是私有&#xff0c;struct是共有 私有的好处&#xff1a;控制数据的有效性&#xff0c;意…

MATLAB练习题:估计离开家之前能拿到报纸的概率

​讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 清风订了一份报纸&#xff0c;送报人可能在早上6&#xff1a;…