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

C 语言编程 — 线程池设计与实现

目录

文章目录

  • 目录
  • 线程池(Thread Pool)
  • tiny-threadpool
    • 数据结构设计
      • Task / Job
      • Task / Job Queue
      • Worker / Thread
      • Thread Pool Manager
    • Public APIs
    • Private Functions
    • 运行示例

线程池(Thread Pool)

线程池(Thread Pool)是一种用于管理多线程环境的技术。Thread Pool 会在 User Process 中预先创建一组 User Threads,并在需要时重复使用它们,而不是频繁的创建新线程。

线程池可以有效提高程序性能和可靠性:

  • 避免频繁创建、销毁线程,降低了系统开销;
  • 限制线程数量,防止过度占用系统资源;
  • 提高了程序的响应速度和吞吐量;
  • 管理线程的生命周期,避免了线程泄漏的风险;
  • 可实现任务优先级。

tiny-threadpool

  • Github:https://github.com/JmilkFan/tiny-threadpool

tiny-threadpool fork 自 C-Thread-Pool,是一个开源的轻量级线程池,实现了以下功能。

  • 符合 ANCI C 和 POSIX 风格;
  • 支持 Thread 的 Pause(暂停)、Resume(恢复)、Wait(等待);
  • 提供简洁的 APIs。

数据结构设计

在这里插入图片描述

Task / Job

Task / Job 本质是由 Producer 发出的任务请求,通常数量庞大,需要高并发的进行处理。

/*** Job 应该包含以下 3 个成员:*  1. 线程入口函数;* 	2. 线程入口函数的参数;* 	3. 指向下一个 Job 的指针。*/
typedef struct job{struct job*  prev;  // 指向下一个 Job,添加 New Job 入队尾(Rear)时,上一次的 Rear Job,应该要指向下一个 New Job,然后 New Job 成为新的 Near Job。void   (*function)(void* arg);  // 线程入口函数的类型声明void*  arg;                     // 线程入口函数的参数的类型声明
} job;

Task / Job Queue

Queue 用于缓存 Jobs,并且是 FIFO 的。在某些场景中,可能会要求 Queue 的长度是可调整的,也可能会要求有多条不同优先级的 Queues。

/*** Job Queue 应该包含以下 5 个成员:*  1. 队头* 	2. 队尾*  3. 队长*  4. 互斥锁,保证高并发 Jobs 入队/出队是 FIFO 的。* 	5. 队列状态:1)空队列;2)非空队列;*/
typedef struct jobqueue{job  *front;              // 指向队头job  *rear;               // 指向队尾int   len;                // 队列长度pthread_mutex_t rwmutex;  // 任务队列的锁bsem *has_jobs;           // 指向一个二元信号量,用于表示 Queue 是否为空。
} jobqueue;/*** 二元信号量,用于标识 Job Queue 是否为空。* 	同样需要使用互斥锁和条件变量来保证高并发处理时二元值的安全性。*/
typedef struct bsem {pthread_mutex_t mutex;  // 信号量的锁pthread_cond_t   cond;  // 信号量的条件int v;                  // 信号量的互斥值//   0:空队列;//   1:非空队列。
} bsem;

Worker / Thread

Worker / Thread 是 Thread Pool 分配出来真正处理 Job 的执行单元,它们是线程入口函数的 Caller(调用者),所以也称为 Consumer。

/*** Thread 应该包含以下 3 个成员:*  1. 友好的 ID,便于调试。区别于 Kernel 分配的 TID。* 	2. 指向 pthread 实体的指针*  3. 指向 Thread Pool 的指针,以此来获得/释放线程池的锁和条件变量*/
typedef struct thread{int       id;              // 友好 IDpthread_t pthread;         // 指向一个 pThread 实体struct thpool_* thpool_p;  // 指向线程池
} thread;

Thread Pool Manager

Thread Pool Manager 用于管理 Thread Pool 资源:例如:创建/销毁多线程、维护任务队列、线程池状态、互斥锁和条件变量等。

当有 Job 需要处理时,Manager 就从 Pool 中获取一个可用的 Thread 来处理。当 Job 完成后,Manager 回收 Thread,而不是销毁它。

/*** Thread Pool Manager 应该包含以下 5 个成员:*  1. 多线程列表*  2. 活跃线程数量* 	3. 工作线程数量(可用线程数 = 活跃线程数量 - 工作线程数量)*  4. 任务队列*  5. 互斥锁*  6. 条件变量*/
typedef struct thpool_{thread**   threads;                // 指向线程指针数组volatile int num_threads_alive;    // 当前活跃的线程数量volatile int num_threads_working;  // 当前工作中的线程数量jobqueue  jobqueue;                // 线程池关联的任务队列pthread_mutex_t  thcount_lock;     // 线程池的锁pthread_cond_t  threads_all_idle;  // 线程池的条件变量
} thpool_;

Public APIs

typedef struct thpool_* threadpool;// 创建一个包含有指定数量线程的线程池
threadpool thpool_init(int num_threads);// 添加 task 到 task queue 中。
int thpool_add_work(threadpool, void (*function_p)(void*), void* arg_p);// 等待所有 tasks 执行完。
void thpool_wait(threadpool);// 暂停所有 tasks,使它们进入 sleep 状态。通过信号机制来实现。
void thpool_pause(threadpool);// 恢复所有 tasks 继续执行。
void thpool_resume(threadpool);// 销毁所有 tasks,如果有 task 正在执行,则先等待 task 执行完。
void thpool_destroy(threadpool);// 获取当前正在工作中的线程数量。
int thpool_num_threads_working(threadpool);

Private Functions

// 构造 struct thread,并调用 pthread_create() 创建线程
static int thread_init (thpool_* thpool_p, struct thread** thread_p, int id) // 当线程被暂停时会在这里休眠
static void thread_hold(int sig_id) // 线程在此函数中执行任务
static void* thread_do(struct thread* thread_p) // 销毁 struct thread
static void thread_destroy (thread* thread_p) // 任务队列相关的操作集合
static int jobqueue_init(jobqueue* jobqueue_p) 
static void jobqueue_clear(jobqueue* jobqueue_p) 
static void jobqueue_push(jobqueue* jobqueue_p, struct job* newjob) 
static struct job* jobqueue_pull(jobqueue* jobqueue_p) 
static void jobqueue_destroy(jobqueue* jobqueue_p) // 信号量相关的操作集合
static void bsem_init(bsem *bsem_p, int value) 
static void bsem_reset(bsem *bsem_p) 
static void bsem_post(bsem *bsem_p) 
static void bsem_post_all(bsem *bsem_p) 
static void bsem_wait(bsem* bsem_p)

运行示例

$ gcc example.c thpool.c -D THPOOL_DEBUG -pthread -o example$ ./example
Making threadpool with 4 threads
THPOOL_DEBUG: Created thread 0 in pool
THPOOL_DEBUG: Created thread 1 in pool
THPOOL_DEBUG: Created thread 2 in pool
THPOOL_DEBUG: Created thread 3 in pool
Adding 40 tasks to threadpool
Thread #245600256 working on 0
Thread #246136832 working on 2
Thread #246673408 working on 3
Thread #246673408 working on 6
Thread #246673408 working on 7
...
Killing threadpool

相关文章:

C 语言编程 — 线程池设计与实现

目录 文章目录目录线程池(Thread Pool)tiny-threadpool数据结构设计Task / JobTask / Job QueueWorker / ThreadThread Pool ManagerPublic APIsPrivate Functions运行示例线程池(Thread Pool) 线程池(Thread Pool&am…...

并发编程要点

Java并发编程中的三大特性分别是原子性、可见性和有序性,它们分别靠以下机制实现: 原子性:原子性指的是对于一个操作,要么全部执行,要么全部不执行。Java提供了一些原子性操作,例如AtomicInteger等&#xf…...

HDFS黑名单退役服务器

黑名单:表示在黑名单的主机IP地址不可以,用来存储数据。 企业中:配置黑名单,用来退役服务器。 黑名单配置步骤如下: 1)编辑/opt/module/hadoop-3.1.3/etc/hadoop目录下的blacklist文件 添加如下主机名称&…...

基于stm32智能语音电梯消毒系统

这次来分享个最近做的项目,stm32智能语音电梯消毒系统功能说明:在电梯,房间,客道区域内,检测到人,则执行相关动作!例如继电器开关灯,喷洒酒精等行为。手机app/微信小程序可以控制需要…...

FreeRTOS系列第1篇---为什么选择FreeRTOS?

1.为什么学习RTOS? 作为基于ARM7、Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS。不仅因为不恰当的使用RTOS会给项目带来额外的稳定性风险,更重要的是我认为绝大多数基于ARM7、Cortex-M3硬件的项目,还没复杂到使用RTOS的地…...

基于.NET Core内置浏览器窗体应用程序界面框架

更多开源项目请查看:一个专注推荐.Net开源项目的榜单 平常我们在做项目过程中,桌面软件具备操作高效、利用本地计算机做一些复杂运算、或者设定快捷操作等优势,但是桌面软件也有很多缺点,比如升级问题、系统兼容问题、系统bug排查…...

【数据结构初阶】一文带你学会归并排序(递归非递归)

目录 前言 递归实现 代码实现 非递归实现 代码实现 总结 前言 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 作为一种典型的分而治之思想…...

Simulink壁咚(一)——What and How

目录 一、前言 二、Simulink 知多少 三、滤波算法 四、Model Verification 五、Model Coverage 六、Simulink测试实例 七、Simulink Test 八、Test Manager 九、Test Harness 十、 学习 一、前言 Simulink从2017b以后更加工程化和实用化,基于MBD的功能日趋…...

【PyTorch】Pytorch基础第0章

本文参加新星计划人工智能(Pytorch)赛道:https://bbs.csdn.net/topics/613989052 这是目录PyTorch的简介PyTorch 构建深度学习模型的步骤搭建pytorch使用环境PyTorch的简介 PyTorch 是一个开源的机器学习框架,由 Facebook 的人工智能研究院(…...

Android学习总结

积累熟练掌握 Java 语言,面向对象分析设计能力,反射原理,自定义注解及泛型,多次采用设计模式重构公司项目;熟练掌握 IVM 原理,反射,动态代理以及对 ClassLoader 热修复有比较深的理解&#xff1…...

虚拟机ubuntu安装samba服务

安装samba apt-get install samba 新建一个共享目录 mkdir /home/l/work chmod 777 /home/l/work 配置服务 配置 /etc/samba/smb.confsudo smbpasswd -a l(添加用户名名称) 防火墙关闭 Ubuntu中 我们使用命令查看当前防火墙状态; sudo ufw status inactive状态是防火墙关闭…...

开发板中的内存压力测试,你了解多少?

1. 测试目的内存压力测试的目的是评估开发板中的内存子系统性能和稳定性,以确保它能够满足特定的应用需求。开发板通常用于嵌入式系统、物联网设备、嵌入式智能家居等场景,这些场景对内存的要求通常比较高。其内存压力测试的主要目的有:1.对确…...

MATLAB | 这些花里胡哨的热图怎么画

好早之前写过一个绘制相关系数矩阵的代码,但是会自动求相关系数,而且画出来的热图只能是方形,这里写一款允许nan值出现,任意形状的热图绘制代码,绘制效果如下: 如遇到bug请后台提出,并去gitee下…...

Java开发的一些编码建议

1、无论是类、方法、字段、变量,尽可能的限制他们的作用范围,可以避免出现不必要的错误;同时虚拟机也能有更大的优化空间。 2、错误越早发现越好,编译时发生错误比在运行时发生错误好。而且编译时错误能更好的定位问题所在。 这…...

【YOLOv8/YOLOv7/YOLOv5/YOLOv4/Faster-rcnn系列算法改进NO.59】引入ASPP模块

前言作为当前先进的深度学习目标检测算法YOLOv8,已经集合了大量的trick,但是还是有提高和改进的空间,针对具体应用场景下的检测难点,可以不同的改进方法。此后的系列文章,将重点对YOLOv8的如何改进进行详细的介绍&…...

C++STL set/multiset容器 构造和赋值 大小和交换 插入和删除 查找和统计

文章目录set/multiset容器1 set容器 基本概念2 set容器 构造和赋值3 set容器 大小和交换4 set容器 插入和删除5 set容器 查找和统计set/multiset容器 1 set容器 基本概念 简介: 所有元素都会在插入时会被自动排序,例如,在set容器放入元素1、…...

产品研发项目进度管理软件工具有哪些推荐?整理10款最佳进度管理软件

项目进度管理是确保项目按时完成的关键过程,使用合适的项目进度管理工具能确保帮助项目管理者实时了解和控制项目的进展情况,及时发现和解决问题,减少项目风险,提高项目效率和管理水平。这里将整理出国内外最受欢迎的10款项目进度…...

「ML 实践篇」分类系统:图片数字识别

目的:使用 MNIST 数据集,建立数字图像识别模型,识别任意图像中的数字; 文章目录1. 数据准备(MNIST)2. 二元分类器(SGD)3. 性能测试1. 交叉验证2. 混淆矩阵3. 查准率与查全率4. P-R 曲…...

从大专到测开,上海某字母站大厂的面试题,岗位是测开(25K*16)

简单介绍一句,大专出身,三年经验。跳了四次槽,面试了无数次,现在把自己的面试经验整理出来分享给大家,堪称必杀技! 1,一切从实际出发,对实际工作进行适当修饰 2,不会的简…...

【面试题】Python软件工程师能力评估试题(一)

文章目录前言应试者需知(一)Python 语言基础能力评估1、理解问题并完成代码:2、阅读理解代码,并在空白处补充完整代码:3、编写一个装饰器:exposer4、阅读代码并在空白处补充完整代码:5、自行用P…...

Java八股文(Java多线程面试题)

并行和并发的区别?(1)并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生;(2)并行是在不同实体上的多个事件,并发是在同一实体上的多个事件&#…...

小程序当前页面如何分享别的页面内容呢?

需求分析 因为功能的需要分为两点 他需要调转转发,并且有首页转发点击button按钮进行转发邀请好友帮忙助力,如何做到一个页面多种转发 如何区分,是button转发还剩右上角三个点转发呢? 通过onShareAppMessage()这个函数的事件…...

编写Java哪个编译器好

现在能够编写Java代码的工具简直不要太多,各种各样五花八门,但目前效率最高的还是Intellij Idea。但这个工具对于完全零基础的小白来说,第一次用起来是比较复杂的,因为它的功能太多了。这就好比你要学开车,如果上来就给…...

第十六章 Java为什么使用序列化

为何要指定serialVersionUID的值如果不指定显示serialVersionUID的值,jvm在序列化时会自动生成一个serialVersionUID,跟属性一起序列化,再进行持久化或者网络传输,在反序列化时,jvm会根据属性自动生成一个新版的serial…...

28岁小公司程序员,无车无房不敢结婚,要不要转行?

大家好,这里是程序员晚枫,又来分享程序员的职场故事了~ 今天分享的这位朋友叫小青,我认识他2年多了。以前从事的是土木行业,2年前找我咨询转行程序员的学习路线和职业规划后,通过自学加入了一家创业公司,成…...

出道即封神的ChatGPT,现在怎么样了?

从互联网的普及到智能手机,都让广袤的世界触手而及,如今身在浪潮中的我们,已深知其力。前阵子爆火的ChatGPT,不少人保持观望态度。现如今,国内关于ChatGPT的各大社群讨论,似乎沉寂了不少,现在怎…...

【计算机视觉】CNN 可视化算法

文章目录一、CAM算法1.1 概述1.2 CAM算法介绍二、Grad-CAM算法2.1 概述2.2 Guided Backpropagation2.3 Occlusion Sensitivity2.4 Grad-CAM 整体结构和效果2.5 Grad-CAM 实现细节一、CAM算法 1.1 概述 本文介绍 2016 年提出的 CAM (Class Activation Mapping) 算法&#xff0…...

自动抓取服务器巡检、登录、执行命令记录+备份脚本

文章目录 引抓取【巡检日志】语言&时区设置语言设置时区巡检脚本执行效果抓取【登录信息】登录脚本登录脚本低版本的last命令执行效果抓取【history记录】说明配置history授权日志文件显示时间戳持久化到日志未配置history的配置过history的执行脚本执行脚本...

如何用Python求解微分方程组

文章目录odeint简介示例odeint简介 scipy文档中将odeint函数和ode, comples_ode这两个类称为旧API,是scipy早期使用的微分方程求解器,但由于是Fortran实现的,尽管使用起来并不方便,但速度没得说,所以有的时候还挺推荐…...

【微信小程序】-- 自定义组件 - behaviors(三十九)

💌 所属专栏:【微信小程序开发教程】 😀 作  者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...

网站备案核验系统/地推app推广赚佣金

出差是不少员工的工作常态,尤其对于那些从事产品销售、运维等工作的员工而言,出差更是家常便饭。一般而言,对公司的合理安排,员工应当服从。然而,如果公司明知员工不适宜出差,却仍然频繁作出异地出差的工作…...

河北建设厅官方网站电话/制作网页多少钱

原帖:http://3dmgame.chnren.com/bbs/showtopic-604395.html 这个是标题,因为去年开始做的时候就采用了这张图做标题,所以最终版也没有更换,只是修饰了一下呵呵。游戏名称:萝莉的远征RPG1ST银色幻境版本信息&#xff1…...

北京网站建设公司网络营销外包网络建站报价/免费网站模板网

1.Redis 事务是什么 可以一次执行多个命令,本质是一组命令的集合。一个事务中的,所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。 2.Redis 事务的作用 一个队列中,一次性、顺序性、排他性的执行…...

暴雪网易2023后不代理了/seo外包费用

查看自己的ip和采用什么方式上网(网通/电信)http://www.whatchina.com/html/sip.asp本文转自 xcf007 51CTO博客,原文链接:http://blog.51cto.com/xcf007/161180,如需转载请自行联系原作者...

做asp动态网站制作流程/建站软件可以不通过网络建设吗

栈与队列就像一对兄弟一样&#xff0c;学习的时候可以一块学习。 栈的特点&#xff1a;先进后出 队列的特点&#xff1a;先进先出 一、头文件 栈的头文件 #include<stack> 队列的头文件 #include<queue> 二、定义 栈的定义&#xff1a;stack<TYPE> s; 队列…...

wordpress站点安装/百度灰色关键词代做

问题描述&#xff1a; rmq消息队列中接收到了消息&#xff0c;并由消费者消费&#xff0c;由于下游服务异常&#xff0c;导致异常抛出&#xff0c;消费者消费消息失败&#xff0c;导致消息一直处于unack&#xff0c;return给rmq-server&#xff0c;重新被消费&#xff0c;但消费…...