基于多反应堆的高并发服务器【C/C++/Reactor】(中)处理任务队列中的任务

 一、处理任务队列中的任务

(1)EventLoop启动 EventLoop初始化和启动

// 启动反应堆模型
int eventLoopRun(struct EventLoop* evLoop) {assert(evLoop != NULL);// 取出事件分发和检测模型struct Dispatcher* dispatcher = evLoop->dispatcher;// 比较线程ID是否正常if(evLoop->threadID != pthread_self()) {return -1;}// 循环进行事件处理while(!evLoop->isQuit) {dispatcher->dispatch(evLoop,2); // 超时时长 2s// 已续写eventLoopProcessTask(evLoop);}return 0;   
}

多加一句eventLoopProcessTask(evLoop); 理由在后文提到!

(2)添加任务到任务队列中(在EventLoop的任务队列中添加新任务)

// 添加任务到任务队列
int eventLoopAddTask(struct EventLoop* evLoop,struct Channel* channel,int type) {// 加锁,保护共享资源pthread_mutex_lock(&evLoop->mutex);// 创建新节点,后添加到任务队列中去struct ChannelElement* node = (struct ChannelElement*)malloc(sizeof(struct ChannelElement));node->channel = channel;node->type = type;node->next = NULL;// 链表为空if(evLoop->head == NULL) {evLoop->head = evLoop->tail = node;}else {evLoop->tail->next = node; // 添加evLoop->tail = node; // 后移}pthread_mutex_unlock(&evLoop->mutex);if(evLoop->threadID == pthread_self()) {// 当前子线程eventLoopProcessTask(evLoop);}else{// 主线程 -- 告诉子线程处理任务队列中的任务// 1.子线程在工作 2.子线程被阻塞了:select、poll、epolltaskWakeup(evLoop);}return 0;
}

小细节:假设说添加任务的是主线程,那么程序就会执行taskWakeup这个函数,主线程执行这个函数对于子线程来说两种情况

第一种情况,它正在干活,对于子线程没有影响,充其量就是它检测的那个集合里边多出来了一个被激活的文件描述符。

第二种情况,如果说此时子线程select、poll、或epoll_wait阻塞了,调用taskWakeup函数可以解除其阻塞。如果解除阻塞了,我们希望子线程干什么事情呢?

  1. 具体流程:因为主线程是在子线程的任务队列里添加了一个任务 先调用taskWakeup函数解除阻塞,让子线程解除阻塞是需要让它去处理任务。接着eventLoopRun函数中调用eventLoopProcessTask(evLoop);
  2. 详解流程:因为这个反应堆模型只要开始运行(eventLoopRun)就会不停的调用dispatch函数,这个dispatch是一个函数指针,底层指向的是poll模型的poll函数,select模型的select函数,epoll模型的epoll_wait函数。如果当前的子线程正在被刚才的提到的这三个函数里边的其中一个阻塞着,此时正好被主线程唤醒了(调用taskWakeup函数)。需要在循环进行事件处理中添加一句eventLoopProcessTask(evLoop);

taskWakeup函数的调用和影响

  1. 主线程调用taskWakeup函数时,子线程可能正在被select、poll、或epoll_wait阻塞
  2. 主线程在子线程的任务队列中添加任务,因此需要让子线程解除阻塞并处理队列中的任务

总结关于任务队列的处理有两个路径:

  1. 第一个路径:子线程往任务队列里边添加一个任务,比如说修改文件描述符里边的事件,肯定是子线程自己修改自己检测的文件描述符的事件,修改完了之后,子线程就直接调用这个函数去处理任务队列里边的任务。
  2. 第二个路径:主线程在子线程的任务队列里边添加了一个任务,主线程是处理不了的,并且主线程现在也不知道子线程是在工作还是在阻塞,所以主线程就默认子线程现在正在阻塞,因此主线程就调用了一个唤醒函数(taskWakeup)来解除阻塞,调用这个函数保证子线程肯定是在运行的,子线程eventLoopRun函数dispatch函数调用位置解除了阻塞,然后调用eventLoopProcessTask(evLoop);
// 启动反应堆模型
int eventLoopRun(struct EventLoop* evLoop) {...// 循环进行事件处理while(!evLoop->isQuit) {dispatcher->dispatch(evLoop,2); // 超时时长 2s// 已续写eventLoopProcessTask(evLoop);}return 0;   
}// 添加任务到任务队列
int eventLoopAddTask(struct EventLoop* evLoop,struct Channel* channel,int type) {...if(evLoop->threadID == pthread_self()) {// 当前子线程eventLoopProcessTask(evLoop);}else{// 主线程 -- 告诉子线程处理任务队列中的任务// 1.子线程在工作 2.子线程被阻塞了:select、poll、epolltaskWakeup(evLoop);}return 0;
}
  • EventLoop.h
// 处理任务队列中的任务
int eventLoopProcessTask(struct EventLoop* evLoop);// 处理dispatcher中的任务
int eventLoopAdd(struct EventLoop* evLoop,struct Channel* channel);
int eventLoopRemove(struct EventLoop* evLoop,struct Channel* channel);
int eventLoopModify(struct EventLoop* evLoop,struct Channel* channel);
  • EventLoop.c

eventLoopProcessTask函数的作用:它处理队列中的任务,需要遍历链表并根据type进行对应处理。

  1. 在加锁和解锁函数之间遍历链表
  2. 需要遍历链表,处理节点,并在处理完后从列表中删除节点
  3. 如果当前节点被处理完,需要移动head指针以处理下一个节点
  4. 需要定义temp指针来保存head指针指向的地址,并在head后移后释放temp指针指向的节点
// 处理任务队列中的任务
int eventLoopProcessTask(struct EventLoop* evLoop) {pthread_mutex_lock(&evLoop->mutex);// 取出头节点struct ChannelElement* head = evLoop->head;while (head!=NULL) {struct Channel* channel = head->channel;if(head->type == ADD) {// 添加eventLoopAdd(evLoop,channel);}else if(head->type == DELETE) {// 删除eventLoopRemove(evLoop,channel);}else if(head->type == MODIFY) {// 修改eventLoopModify(evLoop,channel);}struct ChannelElement* tmp = head;head = head->next;// 释放节点free(tmp);}evLoop->head = evLoop->tail = NULL;pthread_mutex_unlock(&evLoop->mutex);return 0;
}

注意事项

  1. 在写程序时,每个功能应对应一个任务函数,以提高程序逻辑性和可维护性
  2. 在处理任务队列时,需要注意线程安全和资源管理问题

总结

  1. 讲解了任务队列处理函数的作用和实现细节,以及taskWakeup函数的调用和影响
  2. 强调了将功能分散到单独函数中的重要性,以提高程序的可读性和可维护性

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

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

相关文章

2024阿里云Alibaba Cloud Linux 3镜像版本大全说明

Alibaba Cloud Linux阿里云打造的Linux服务器操作系统发行版,Alibaba Cloud Linux完全兼容完全兼容CentOS/RHEL生态和操作方式,目前已经推出Alibaba Cloud Linux 3,阿里云百科aliyunbaike.com分享Alibaba Cloud Linux 3版本特性说明&#xff…

面试算法83:没有重复元素集合的全排列

题目 给定一个没有重复数字的集合,请找出它的所有全排列。例如,集合[1,2,3]有6个全排列,分别是[1,2,3]、[1,3,2]、[2,1,3]、[2,3&…

如何在anaconda里安装basemap和pyproj库

当直接使用conda命令进行安装basemap和pyproj库时,会出现版本不对应的报错问题(如下图),所以此篇博客用以展示如何安装basemap和pyproj库 题主默认使用的anaconda源已经切换成了清华大学源,但是仍然会出现报错,所以不是源的问题&a…

haproxy笔记

文章目录 场景haproxy配置文档地址 场景 还得先从场景说起。 生产环境redis检查,发现配置的redis地址不对。 redis有3个节点。 192.168.0.1 192.168.0.2 192.168.0.3 但是配置的是 192.168.0.9 端口是16379。 好奇怪有没有,是不是配错了? 问了下部署大…

CMake入门教程【核心篇】函数(function)

😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「本文的内容」:CMake入门教程 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 1. 函数的定义与基本…

vue3对比vue2是怎样的

一、前言 Vue 3通过引入Composition API、升级响应式系统、优化性能等一系列的改进和升级,提供了更好的开发体验和更好的性能,使得开发者能够更方便地开发出高质量的Web应用。它在Vue.js 2的基础上进行了一系列的改进和升级,以提供更好的性能、更好的开发体验和更好的扩展性…

labview 与三菱FX 小型PLC通信(OPC)

NI OPC服务器与三菱FX3U PLC通讯方法 一、新建通道名称为:MIT 二、选择三菱FX系列 三、确认端口号相关的参数(COM端:7.波特率:9600,数据位:7,校验:奇校验,停止位&#xf…

海外住宅IP代理的工作原理和应用场景分析,新手必看

海外住宅IP代理作为一种技术解决方案,为用户提供了访问全球网络资源和维护隐私安全的方法。本文将介绍海外住宅IP代理的工作原理和应用场景,帮助读者更好地理解和利用这一技术。 一、工作原理 海外住宅IP代理的工作原理基于代理服务器和IP地址的转发。它…

ITSS服务工程师vs ITSS服务经理:哪个职位更适合你?

✨在信息技术服务领域,ITSS服务工程师和ITSS服务经理是两个极具吸引力的职位。但它们各自的特点和要求是什么?哪个更适合你的职业规划和个人兴趣?接下来,我们将为你详细解读这两个职位的区别,帮助你做出明智的选择&…

Win32 基本程序设计原理总结

目录 1. Windows系统 基本原理 2. 需要什么函数库(.LIB) 2.1 C Runtimes: 2.2 Windows API 3. 需要什么头文件(.H) 4. Windows 程序运行的本质 5. 窗口类的注册与窗口的诞生 6.消息 6.1 消息分类:…

HTML基础知识 【一篇就够】

文章目录 html是什么?html的历史html的版本html的基本结构常用的html标签常用属性html中的注释html元素和标签的区别 html文本格式化标题和段落粗体和斜体下划线和删除线超链接图像标签列表标签表格标签 html表单表单标签文本框、密码框和多行文本框单选框和复选框下…

咖啡茶饮营销不止「9 块 9」,门店「VACS」需要全面提升

每一座城市 CBD 的写字楼下和热门商圈的街边,都是咖啡茶饮的战场。作为餐饮行业的热门赛道,咖啡茶饮近年来一直保持高速增长。据统计,截至今年 10 月 31 日,陆陆续续又有约 15 万家店铺开门营业…… 白热化竞争下,茶饮…

modbus tcp通讯

配置pom.xml <dependency><groupId>com.infiniteautomation</groupId><artifactId>modbus4j</artifactId><version>3.0.3</version> </dependency><repositories><repository><releases><enabled>…

2023到2024年:前端发展趋势展望

本文探讨了2023年至2024年之间前端领域的发展趋势。我们将关注以下几个方面的变化&#xff1a;无代码/低代码开发的兴起、WebAssembly的广泛应用、跨平台技术的发展、人工智能在前端的应用以及用户体验的不断优化。 随着技术的飞速发展&#xff0c;前端开发在推动互联网与移动应…

Google Gemini接口调用(node版)

一、打开Google AI Studio https://makersuite.google.com/app/apikey 二、在国外服务器上部署一个接口用于真正的请求 const sdAxiosOnAzure async (req, res) > {let {config {url: https://sinkin.ai/api/inference,method: post,data: {},timeout: 30 * 60 * 1000,}…

计算机网络期末复习题(一)

文章目录 第一章第二章第三章第四章第五章第六章 第一章 1.在OSI七层结构模型中&#xff0c;处于数据链路层与传输层之间的是&#xff08;&#xff09; 选项A&#xff1a;物理层 选项B&#xff1a;网络层 选项C&#xff1a;会话层 选项D&#xff1a;表示层 正确答案&#xff…

Python爬虫中的协程

协程 基本概念 协程&#xff1a;当程序执行的某一个任务遇到了IO操作时&#xff08;处于阻塞状态&#xff09;&#xff0c;不让CPU切换走&#xff08;就是不让CPU去执行其他程序&#xff09;&#xff0c;而是选择性的切换到其他任务上&#xff0c;让CPU执行新的任务&#xff…

网络安全—认证技术

文章目录 加密认证对称密钥体制公钥密码体制公钥的加密公钥身份认证和加密 鉴别码认证MAC鉴别码 报文摘要认证认证 加密只认证数字签名 通过了解以前前辈们使用的消息认证慢慢渐进到现代的完整的认证体系。所以在学习的时候也很蒙圈&#xff0c;因为前期的很多技术都是有很严重…

这次,数据泄露的目标受害者指向了---救护车服务公司

已停业的救护车服务遭到勒索软件攻击导致近百万人受到威胁&#xff01; 此次数据泄露的目标受害者是法伦救护车服务公司&#xff0c;该公司是Transformative Healthcare的子公司。ALPHV勒索软件团伙声称对2023年4月下旬对Transformative Healthcare的攻击负责&#xff0c;并导…

Docker命令---重新启动容器

介绍 使用docker命令重新启动容器 示例 docker restart 容器ID或者容器名