基于多反应堆的高并发服务器【C/C++/Reactor】(中)线程池的启动和从线程池中取出一个反应堆实例

一、线程池的启动 (主线程)

// 启动线程池 (主线程)
void threadPoolRun(struct ThreadPool* pool) {/*线程池被创建出来之后,接下来就需要让线程池运行起来,其实就是让线程池里的若干个子线程运行起来*/// 确保线程池未运行  assert(pool && !pool->isStart);// 比较主线程的ID和当前线程ID是否相等 // 相等=>确保执行线程为主线程;不相等=>exit(0)if(pool->mainLoop->threadID != pthread_self()) {exit(0);}pool->isStart = true; // 标记为启动if(pool->threadNum > 0) { // 线程数量大于零for(int i=0;i<pool->threadNum;++i) {workerThreadInit(&pool->workerThreads[i], i);// 初始化子线程workerThreadRun(&pool->workerThreads[i]); // 启动子线程}}
}

## 学习笔记:线程池的运行机制

  • 线程池被创建后,需要启动使其子线程运行。启动线程池的函数需要一个有效struct ThreadPool*类型指针pool作为参数,和threadNum代表子线程总个数
// 初始化线程池
struct ThreadPool* threadPoolInit(struct EventLoop* mainLoop, int threadNum);
  • 确保线程池未运行且执行线程为主线程
// 确保线程池未运行
assert(pool && !pool->isStart);
// 比较主线程的ID和当前线程ID是否相等 
// 相等=>确保执行线程为主线程;不相等=>exit(0)
if(pool->mainLoop->threadID != pthread_self()) {exit(0);
}

如果条件满足,将线程池标记为已启动,并初始化并启动子线程;如果线程数量大于零,通过WorkerThread模块的workerThreadInit函数进行初始化,通过WorkerThread模块的workerThreadRun函数进行启动;如果线程数量为零,线程池可以提供主线程的反应堆模型(mainLoop)

pool->isStart = true; // 标记为启动
if(pool->threadNum > 0) { // 线程数量大于零for(int i=0;i<pool->threadNum;++i) {workerThreadInit(&pool->workerThreads[i], i);// 初始化子线程workerThreadRun(&pool->workerThreads[i]); // 启动子线程}
}

### 知识点:线程池的启动

  • 启动线程池的函数需要确保传入的结构体指针有效且线程池未运行
  • 执行线程需要判断是否为主线程,避免异常情况
  • 成功启动后,需要初始化并启动子线程,通过WorkerThread模块的函数进行初始化和启动
  • 如果线程数量为零,线程池可以提供主线程的反应堆模型(mainLoop) 

二、从线程池中取出一个反应堆实例 (主线程)

此外,takeWorkerEventLoop函数 主线程可以从线程池中取出某个子线程的反应堆实例。

目的:这个函数是主线程调用的,因为主线程是拥有线程池的。因此主线程可以遍历线程池里边的子线程,从中挑选一个子线程,得到它的反应堆模型,再将处理的任务放到反应堆模型里边。

// 取出线程池中的某个子线程的反应堆实例
struct EventLoop* takeWorkerEventLoop(struct ThreadPool* pool) {assert(pool->isStart);// 确保线程池是运行的// 比较主线程的ID和当前线程ID是否相等 // 相等=>确保执行线程为主线程;不相等=>exit(0)if(pool->mainLoop->threadID != pthread_self()) {exit(0);}// 从线程池中找到一个子线程,然后取出里边的反应堆实例struct EventLoop* evLoop = pool->mainLoop; if(pool->threadNum > 0) {evLoop = pool->workerThreads[pool->index].evLoop;pool->index = ++pool->index % pool->threadNum;}return evLoop;
}

如果线程数量为零,evLoop 为主线程的反应堆模型(mainLoop),即:

evLoop=pool->mainLoop;

如果线程数量大于零,从线程池中的某个子线程获取其事件循环,并将其存储在evLoop变量中。为了对线程池中的工作线程实现雨露均沾,故需要用到index这个变量,为了确保 pool->index  的值在合适的取值范围内并且不会超出它的取值范围:先将 pool->index  的值加一,然后对 pool->threadNum取余数,并将结果赋值给 pool->index :

① pool->index++;② pool->index %= pool->threadNum;

=>③ pool->index = ++pool->index % pool->threadNum;

if(pool->threadNum > 0) {evLoop = pool->workerThreads[pool->index].evLoop;pool->index = ++pool->index % pool->threadNum;
}

 ### 知识点:子线程的反应堆实例的取出

  • 可以通过takeWorkerEventLoop函数从线程池中取出子线程的反应堆实例
  • 这个函数的核心是取出反应堆实例,用于处理任务
  • 如果线程数量为零,evLoop 为主线程的反应堆模型(mainLoop)
  • 对线程池中的工作线程实现雨露均沾地分配各个子线程调度,避免所有任务都由同一个线程处理,还确保index在合适的取值范围

>>总结:

        本文主要讲述了线程池的启动过程和操作函数。在启动线程池时,需要传入有效指针,确保线程池未被运行,并判断执行线程的线程是否为主线程。通过WorkerThread模块中的函数对子线程进行初始化并启动。主线程可以方便地管理子线程,并从中选择一个子线程以获取其反应堆模型。

        此外,还讲述了线程池操作的函数,包括初始化、启动和取出子线程等。整个处理流程需要确保每个任务都能被雨露均沾地分配给各个子线程,避免所有任务都由同一个线程处理,还确保了index在合适的取值范围。

>>线程池总结:

// 初始化线程池
struct ThreadPool* threadPoolInit(struct EventLoop* mainLoop, int threadNum);// 启动线程池 
void threadPoolRun(struct ThreadPool* pool);// 取出线程池中的某个子线程的反应堆实例
struct EventLoop* takeWorkerEventLoop(struct ThreadPool* pool);

threadPoolInit函数、threadPoolRun函数、takeWorkerEventLoop函数都需要在主线程里边进行依次调用。首先调用threadPoolInit函数得到pool实例,之后调用threadPoolRun函数启动线程池(意味着里边的子线程会启动)。接着调用takeWorkerEventLoop函数取出线程池中的某个子线程的反应堆实例,再把这个实例给到调用者,调用者就可以通过这个实例,往它的任务队列里边添加任务,这个任务添加到evLoop的任务队列里边去了之后,就开始处理任务队列。然后再根据任务队列里边的节点类型来处理Dispatcher的检测集合。有三种情况:

  • 情况1.往检测集合里边添加新的节点
  • 情况2.从检测集合里边删除一个节点
  • 情况3.修改检测集合里边某个文件描述符对应的事件

Dispatcher这个检测集合被处理完之后,这个反应堆模型开始进行一个循环,它需要循环调用底层的poll/epoll_wait/select函数来检测这个集合里边是否有激活的文件描述符。如果有激活的文件描述符,那么就通过这个文件描述符找到它所对应的channel。找到这个channel之后,再基于激活的事件调用事件对应的回调函数。这个函数调用完成之后,对应的事件也就处理完毕。这就走完了整个的处理流程

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

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

相关文章

小微企业在银行信贷相关产品和机器学习建模案例_论文科研_企业调研

各银行小微企业贷款业务 互联网的时代&#xff0c;大量新信息技术的涌现和网络的无处不在&#xff0c;想要抢占这片金融天地&#xff0c;必须重视小微金融业务&#xff0c;小微企业是一直具有重大潜力的客户&#xff0c;商业银行、消金公司发展小微信贷业务可以拓宽自身客户群…

java公交系统毕业论文

公交系统毕业论文 毕业设计题目:基于Java的公交车查询系统的设计与实现 年 月 日 毕 业 设 计 中 文 摘 要 随着中国经济的快速发展&#xff0c;我国交通运输业也在不断的优化发展。公交车的站点和线路的增多也给人们的出行带来了极大的不便&#xff0c;特别是针对一些旅客…

系统学英语 — 音标音节 — 能读就能写

目录 文章目录 目录概览12 个单元音8 个双元音28 个辅音音节 概览 12 个单元音 序号发音音标助记字母组合备注1拖长音 前腔[i:]eate、ea、ee、ie2短促音 前腔[i]bige、i、y3拖长音 后腔[a:]aska、ar4短促音 中腔[ʌ]runu、o、ou、oo5拖长音 中腔[ə:]earlyer、ir、or、ur…

Python群论:置换和置换群

文章目录 简介置换的复合置换群 简介 所谓置换&#xff0c;简单地说就是交换两个元素的位置。例如&#xff0c;给定一组元素 a 0 , a 1 , a 2 a_0, a_1, a_2 a0​,a1​,a2​&#xff0c;那么通过置换之后&#xff0c;这组元素可以变成 a 0 , a 2 , a 1 a_0, a_2, a_1 a0​,a2​…

SpringBoot配置多数据源

SpringBoot配置多数据源 前置条件数据库配置pom.xmlapplication.yml代码Two.javaTwoMapper.javaTwoMapper.xmlTwoService.javaTwoServiceImpl.javaTwoController.java效果前置条件 项目已经集成了mysql单数据源 数据库 数据库demo CREATE TABLE `test` (`id` int(11) NOT NUL…

LLM漫谈(二)| QAnything支持任意格式文件或数据库的本地知识库问答系统

一、QAnything介绍 QAnything (Question and Answer based on Anything) 是致力于支持任意格式文件或数据库的本地知识库问答系统&#xff0c;可断网安装使用。 您的任何格式的本地文件都可以往里扔&#xff0c;即可获得准确、快速、靠谱的问答体验。 目前已支持格式: PDF&…

基于商品列表的拖拽排序后端实现

目录 一&#xff1a;实现思路 二&#xff1a;实现步骤 二&#xff1a;实现代码 三&#xff1a;注意点 一&#xff1a;实现思路 后台实现拖拽排序通常需要与前端进行配合&#xff0c;对商品的列表拖拽排序&#xff0c;前端需要告诉后端拖拽的元素和拖动的位置。 这里我们假…

MySQL第四战:视图以及常见面试题(上)

目录 目录&#xff1a; 一.视图 1.介绍什么是视图 2.视图的语法 语法讲解 实例操作 二.MySQL面试题 1.SQL脚本 2.面试题实战 三.思维导图 目录&#xff1a; 随着数字化时代的飞速发展&#xff0c;数据库技术&#xff0c;特别是MySQL&#xff0c;已经成为IT领域中不可…

Java-网络爬虫(二)

文章目录 前言一、WebMagic二、使用步骤1. 搭建 Maven 项目2. 引入依赖 三、入门案例四、核心对象&组件1. 核心对象SipderRequestSitePageResultItemsHtml&#xff08;Selectable&#xff09; 2. 四大组件DownloaderPageProcessorSchedulerPipeline 上篇&#xff1a;Java-网…

使用Enterprise Architect绘制架构图

如何使用Enterprise Architect绘制架构图 之前没有使用过Enterprise Architect软件绘制&#xff0c;目前由于工作需求&#xff0c;需要使用Enterprise Architect绘制一些架构图&#xff0c;现在只使用Enterprise Architect绘制过简单的Flow Chart&#xff0c;想请教一下大神们…

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《考虑系统调峰需求与光热电站收益平衡的储热容量优化配置》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主的专栏栏目《论文与完整程序》 这个标题表明研究的主题涉及到光热电站系统中的储热容量优化配置&#xff0c;而优化的目标是在系统中实现调峰需求并平衡光热电站的收益。让我们逐步解读这…

学习使用layPage, 多功能JS分页组件/插件的方法

学习使用layPage, 多功能JS分页组件/插件的方法 效果图分页代码 效果图 点击查看链接 分页代码 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>Layui</title><meta name"renderer" content"we…

数字系统课程设计与VHDL报告

获“优”&#xff0c;含实验结果视频、代码、报告&#xff0c;99.99%原创&#xff0c;配置环境太复杂不包跑通&#xff0c;要的私信。

在 Docker 中配置 MySQL 数据库并初始化 Project 项目

1. 文件准备 1.1. 添加 SQL 文件头部内容 每个 SQL 文件的头部需要添加以下内容&#xff1a; DROP DATABASE IF EXISTS xx_..; CREATE DATABASE xx_..; USE xx_..;1.2. 修改 AUTO_INCREMENT 在每个 SQL 文件中&#xff0c;将 AUTO_INCREMENT 修改为 1。 1.3. 插入机型 在 SQL…

软件测试|深入学习 Docker Logs

简介 Docker 是一种流行的容器化技术&#xff0c;它能够帮助用户将应用程序及其依赖项打包成一个可移植的容器。Docker logs 是 Docker 提供的用于管理容器日志的命令&#xff0c;本文将深入学习 Docker logs 的使用和管理&#xff0c;帮助用户更好地监测和解决容器问题。 Do…

QT c++和qml交互实例

文章目录 一、demo效果图二、c和qml交互的基本方式1、qml访问C类对象 三、关键代码1、工程结构图2、c代码MainWindow.cppMainQuickView.cppStudentInfoView.cppStudentInfoModel.cpp 3、qml代码main.qmlMainQuickTopRect.qmlMainQuickMiddleRect.qmlMainQuickMiddleTableRect.q…

蓝桥杯基础知识2 全排列 next_permutation(), prev_permutation()

蓝桥杯基础知识2 全排列 next_permutation()&#xff0c; prev_permutation() #include<bits/stdc.h> using namespace std;int a[10];int main(){for(int i 1; i < 4; i)a[i] i; //4*3*2*1 24bool tag true;while(tag){for(int i1; i < 4; i)cout << a[…

CoTracker 环境配置与ORB 特征点提取结合实现视频特征点追踪

CoTracker 环境配置&与ORB 特征点提取结合实现视频特征点追踪 文章目录 CoTracker 环境配置&与ORB 特征点提取结合实现视频特征点追踪Step1&#xff1a;配置 CoTracker 环境Step2&#xff1a;运行官方的例程Step3&#xff1a;结合 ORB 特征点提取结果展示&#xff1a; …

蓝桥杯练习题(一)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;一&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

时间序列预测 — VMD-LSTM实现单变量多步光伏预测(Tensorflow):单变量转为多变量预测多变量

目录 1 数据处理 1.1 导入库文件 1.2 导入数据集 ​1.3 缺失值分析 2 VMD经验模态分解 2.1 VMD分解实验 2.2 VMD-LSTM预测思路 3 构造训练数据 4 LSTM模型训练 5 LSTM模型预测 5.1 分量预测 5.2 可视化 时间序列预测专栏链接&#xff1a;https://blog.csdn.net/qq_…