基于多反应堆的高并发服务器【C/C++/Reactor】(中)EventLoop初始化

这个Dispatcher是一个事件分发模型,通过这个模型,就能够检测对应的文件描述符的事件的时候,可以使用epoll/poll/select,前面说过三选一。另外不管是哪一个底层的检测模型,它们都需要使用一个数据块,这个数据块就叫做DispatcherData。除此之外,还有另外一个部分,因为在这个反应堆模型里边对应一系列的文件描述符,都属于epoll/poll/select,但是这些文件描述符,它们不是固定的。

  1. 可能我们和客户端新建立了一个连接,那么就需要把某个节点就是某个文件描述符添加到这个Dispatcher模型上边
  2. 或者说服务器和客户端断开连接了,对应的这个文件描述符,就需要从Dispatcher对应的检测集合中删除
  3. 还有一种情况就是要修改Dispatcher检测的这些文件描述符对应的事件

对于刚才描述的这三种情况,不管是哪一个,都可以把它们称为任务。既然是任务,如果产生了多个这样的任务,就需要把这些任务存储起来,所以对应的就需要有一个任务队列。在C语言里边是没有所谓现成的任务队列可直接拿来使用.C++中就有list,可以直接拿一个队列来直接用,或者说拿一个list来直接用,在C语言里边,我们只能自己写了。

既然它是一个任务队列,也就意味着这个队列里边的节点的个数是不固定的,所以我们就需要一个动态的模型,可以实现一个链表。这个链表的节点是什么类型的?是ChannelElement类型.所谓ChannelElement类型。它里边主要其实是一个Channel,还有下一个节点的指针。通过指向下一个节点的指针,就可以把每一个节点连接起来了。当这个任务队列里边有了任务之后,我们就需要通过一个循环,把链表里边所有的节点都读出来。

  •     如果这是一个添加事件的节点,那么我们就把这个文件描述符添加到Dispatcher对应的检测集合中。
  •     如果它是删除的,那么我们就把这个文件描述符从Dispatcher的检测集合中删除。
  •     如果它是修改事件,那么我们就把这个节点在Dispatcher中的事件做一个修改。

这个EventLoop里边有一个任务队列,可以说这个EventLoop它是一个生产者和消费者模型

  • 消费者是谁呢?
    • 就是这个Dispatcher
  • 生产者是谁呢?
    • 生产者有可能是其他的线程,比如说主线程和客户端建立了连接,剩下的事就是通信。如果要通信,就对应一个通信的文件描述符。主线程就把这个任务添加到了子线程对应的这个EventLoop里边。此时在taskQueue里边就多出来了一个节点。在遍历这个任务队列的时候,读到这个节点之后,就需要把当前的这个节点添加到Dispatcher对应的检测模型里边。

另外,在这个EventLoop里边,还有一个ChannelMap,这个ChannelMap也是我们实现的,是通过一个数组来实现的。基于这个ChannelMap,就能够通过一个文件描述符得到对应的那个channel,为什么要得到那个channel呢?因为在这个channel里边有文件描述符,它的读事件写事件对应的回调函数,就是事件触发之后,执行什么样的处理动作。

【思考】什么时候用到了这个ChannelMap了呢?

在实现epoll/select/poll的时候,分别调用了epoll_wait函数/select函数/poll函数,通过遍历内核传出来的这个集合,就得到了触发对应事件的那个文件描述符。但我们现在处理不了,因为得不到对应的channel,我们可以通过EventLoop里边提供的这个ChannelMap就能够得到对应的Channel指针,这个Channel指针就可以调用事件对应的处理函数了。

这三大块之外,还有一些其他的数据成员,比如threadID。因为在当前的服务器里边有多个EventLoop,每个EventLoop都属于一个线程。所以我们可以记录一下这个EventLoop它所对应的那个子线程的线程ID。关于子线程的这个名字肯定是我们给它起的,因为子线程创建出来之后,它只有一个ID,这是系统分配的。关于它的名字,操作系统是没有告诉我们的。

ThreadCondition是条件变量,可用于阻塞线程

【思考】ThreadMutex这个互斥锁它保护的是什么?

其实它保护的是这个任务队列。为什么要保护任务队列呢?对于这个EventLoop来说,它能够被多少个线程操作呢?

  • 如果是主线程的EventLoop,那就是一个。
  • 如果是子线程的EventLoop,那就有可能是两个,为什么是两个呢?
    • 当前,线程在执行这个EventLoop的时候,它肯定要遍历这个taskQueue吧,也就是当前线程需要读这个任务队列。
    • 除此之外,如果主线程和客户端建立了一个连接,主线程是有可能要把一个任务添加到这个EventLoop,对应的任务队列里边,就是额外的另一个线程了。
    • 如果涉及到两个线程操作,同一块共享资源,那么我们是要通过互斥锁来保护这个共享资源的。如果不保护,肯定就会出现数据混乱。

整个项目的结构,在当前这个多反应堆模型的服务器程序里边,它是有多个EventLoop模型的。首先,在主线程里边就有一个EventLoop主线程的,这个EventLoop去检测客户端有没有新的连接到达。如果有新连接,就建立新连接。之后,主线程把这个通信的任务给到线程池里边,把主线程的那个EventLoop也传进来。一定要注意这个EventLoop和主线程的EventLoop是同一个实例。也就是说,线程池里边的这个MainEventLoop和外边这个MainEventLoop它们对应的是同一块内存地址

另外,在线程池里边还有若干个子线程,每个子线程里边都对应一个EventLoop。每个子线程里边的EventLoop它们主要是处理通信的文件描述符相关的操作。这些都是在子线程里边来完成的:

  • 比如说要把一个通信的文件描述符添加到EventLoop里边。
  • 如果服务器和客户端断开连接了,那么就需要把通信的文件描述符从EventLoop里边删除或者要修改这个通信的文件描述符检测的事件

【思考】那么,为什么右侧的TcpConnection里边也有一个EventLoop呢?

关于这个TcpConnection,其实它是封装了用于通信的文件描述符,在这个模块里边,是把子线程里边那个EventLoop的地址传递给了TcpConnection。

在每个线程里边,都有一个EventLoop,也就是说EventLoop是属于线程的,不管是主线程还是子线程,里边都有一个EventLoop然后在这个TcpConnection里边,也有一个EventLoop,但是不是说EventLoop属于TcpConnection,而是TcpConnection属于EventLoop

如果TcpConnection,它属于EventLoop,那么这个TcpConnection就属于对应的某一个子线程。EventLoop属于哪个子线程,这个TcpConnection它就属于哪个子线程。它对应的那些任务处理就是和客户端通信,接收数据以及发送数据的操作就在哪个子线程里边来完成。在线程池里边传进来了一个主线程EventLoop,主线程的EventLoop也是一个反应堆实例。

【思考】为什么要把主线程的反应堆实例传递给线程池呢?

是因为我们在给线程池做初始化的时候,如果指定线程池的子线程个数为0,此时线程池就没有了,不能工作。

为了能够保证线程池能够工作,也就传进来了一个主线程的反应堆实例,在没有子线程的情况下,那么就借用主线程的反应堆实例来完成对应的这一系列的任务处理。在此时,客户端和服务器建立连接之后,得到了用于通信的文件描述符,这个通信的文件描述符被TcpConnection封装起来了。我们就需要把这个TcpConnection放到一个反应堆模型里边,就是放到主线程的EventLoop里边,这样客户端和服务器的通信操作也就能实现了。这种比较极端的情况,对于程序来说,它就是一个单反应堆模型。

  • 如果在创建线程池的时候指定这个子线程的个数大于0,那么就是一个多反应堆的服务器模型。
  • 如果在创建线程池的时候指定线程的个数等于0,此时就是一个单反应堆的服务器模型。

未完待续~

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

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

相关文章

vue3 vue3-print-nb 实现打印功能

vue3 vue3-print-nb 实现打印功能 效果 vue3-print-nb 文档 安装 pnpm add vue3-print-nbtypescript 中 xx.d.ts declare module "vue3-print-nb";配置 全局配置 src/main.ts import print from "vue3-print-nb";const app createApp(App); app.us…

Leetcode2928. 给小朋友们分糖果 I

Every day a Leetcode 题目来源:2928. 给小朋友们分糖果 I 解法1:暴力 枚举 3 位小朋友的糖果数,范围为 [0, limit],分别记为 i、j、k。 当满足 i j k n 时,答案 1。 代码: /** lc appleetcode.c…

引领制造业迈向智能化新时代,SIA上海智能工厂展助力行业蓬勃发展

当今制造业迎来了数字化革命的潮流,其中智能工厂作为其中的一个关键角色,正在推动着制造业的转型和升级。智能工厂不仅仅是一个集成了先进技术的制造厂房,更是数字化时代制造业发展的崭新范本。本文将探讨智能工厂在现代制造业中的重要作用。…

微盛·企微管家:用户运营API集成,电商无代码解决方案

连接电商平台的新纪元:微盛企微管家 随着电子商务的蓬勃发展,电商平台的高效运营已经成为企业成功的关键。在这个新纪元里,微盛企微管家以其创新的无代码开发连接方案,成为企业之间连接电商平台的强大工具。它允许企业轻松集成电…

SecuSphere:一款功能强大的一站式高效DevSecOps安全框架

关于SecuSphere SecuSphere是一款功能强大的一站式高效DevSecOps解决方案,DevSecOps作为一个经过针对性设计的集中式平台,可以帮助广大研究人员管理和优化漏洞管理、CI/CD管道集成、安全评估和DevSecOps实践。 SecuSphere是一个功能全面的DevSecOps平台…

RK3568驱动指南|第八篇 设备树插件-第83章 设备树插件驱动分析实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…

IDEA 控制台中文出现乱码问题解决

一、问题概述 请看下图 二、问题分析 IDEA控制台输出乱码一般会有三种来源: ① IDEA本身编码错误 ② Tomcat日志输出编码错误 ③ 项目本身原因。 终极原因:IDEA编码和Tomcat编码不一致,统一设置为UTF-8即可。 三、解决思路 修改…

C++中的左值,右值和移动语义详解

左值,右值与移动语义 左值表示了一个占据内存中某个可识别位置的对象。右值是无法寻址的临时对象或表达式的值。左值可以隐式地转换为右值,而右值不可。右值可以显式地赋值给左值。赋值运算符、取地址符、内置解引用运算符、下标运算符、内置类型和迭代…

跨域怎么解决

跨域解决主要有以下⼏种: JSONP CORS Nginx代理 document.domain window.name postMessageiframe 1.JSONP 我们知道写 HTML 代码的时候,加⼊图⽚链接就不会有获取不到图⽚的问题。这是因为图 ⽚资源并没有进⾏ ajax 请求,⽽且 script…

Superset二次开发之环境部署(Windows版)

本地环境版本介绍: 编号 名称 版本 1supersetv3.0.0rc32Pythonv3.10.123Nodev16.20.24npmv8.19.45Anacondav3 1.下载源码 #下载源码 git clone https://github.com/apache/superset.git ##速度慢可替换为 https://gitclone.com/github.com/apache/superset.git #进入项目目录…

前端性能优化四十七:工程目录设计范式种类

1. 模块化: ①. 将一个复杂应用根据预设规范封装为多个块并组合起来:a. 对内实现数据私有化b. 对外暴露接口、其它模块通信②. 在前端工程化具体体现:a. 在文件层面上对代码与资源实现拆分与组装b. 将一个大文件拆分为互相依赖的小文件,再统一拼装与加载1. 工程目录设计范式种…

搜维尔科技:Geomagic Phantom Premium 1.5六自由度力反馈设备开箱测试!

搜维尔科技:Geomagic Phantom Premium 1.5六自由度力反馈设备开箱测试! Geomagic Phantom系列产品中首屈一指的力反馈产品Phantom Premium 六自由度力反馈设备(原Sensable)能够提供高度精确的3D对象操作,使用户能够探索…

在Go中解析HTTP请求中的表单数据

想象一下,你收到了一封神秘的信件,信上写着:“在HTTP请求的表单数据中,隐藏着一座宝藏,等待勇敢的冒险者前来寻找。” 你知道,这封信正是冲着你来的!今天,我们将使用Go语言作为我们的…

VMware17Pro虚拟机安装Linux CentOS 7.9(龙蜥)教程(超详细)

目录 1. 前言2. 下载所需文件3. 安装VMware3.1 安装3.2 启动并查看版本信息3.3 虚拟机默认位置配置 4. 安装Linux4.1 新建虚拟机4.2 安装操作系统4.2.1 选择 ISO 映像文件4.2.2 开启虚拟机4.2.3 选择语言4.2.4 软件选择4.2.5 禁用KDUMP4.2.6 安装位置配置4.2.7 网络和主机名配置…

GBASE南大通用数据库分享访问多个数据库的 SQL 语句

您可跨数据库和跨数据库服务器实例运行下列 SQL 语句: • CREATE DATABASE • CREATE SYNONYM • CREATE VIEW • DATABASE • DELETE • DROP DATABASE • EXECUTE FUNCTION • EXECUTE PROCEDURE • INFO • INSERT • LOAD • LOCK TABLE • MERGE • SE…

web自动化测试的智能革命:AI如何推动软件质量保证的未来

首先这个标题不是我取的,是我喂了关键字让AI给取的,果然非常的标题党,让人印象深刻,另外题图也是AI自动生成的。 先简单回顾一下web自动化测试的一些发展阶段 QTP时代 很多年前QTP横空出世的时候,没有人会怀疑这种工…

java判断时间是否为节假日(或指定的日期),是的话返回true,否返回false

这个方法属实有点老套,先定义set,需要手动输入要判断的时间才行。 这个代码,就是输入一个日期,来判断这个日期是否为你指定的日期。如果是的话,返回true,否的话返回false。 代码: package Lx…

软考高级考完了,怎么评职称?

每年考试结束后,总有朋友问我,考完后怎么才能评上职称呢?获得证书就意味着获得了职称吗?让我们一起来看看具体情况吧! 01\职称获取途径 获得职称可以通过认定、评审、国家统一考试(以考代评)、职业资格对应等多种方式…

轻松设置CentOS IP地址的最终指南:详细的分步说明

轻松设置CentOS IP地址的最终指南 一、引言二、准备工作三、手动设置IP地址四、自动分配IP地址(DHCP)五、使用网络管理工具设置IP地址5.1、使用nmtui工具进行图形化设置5.2、使用nmcli命令行工具进行设置 六、常见问题和解决方案七、总结 一、引言 CentOS操作系统是一种基于Li…