基于多反应堆的高并发服务器【C/C++/Reactor】(中)添加 删除 修改 释放

2024-01-04 12:52

本文主要是介绍基于多反应堆的高并发服务器【C/C++/Reactor】(中)添加 删除 修改 释放,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在上篇文章(处理任务队列中的任务)中我们讲解了处理任务队列中的任务的具体流程,eventLoopProcessTask函数的作用:

  • 处理队列中的任务,需要遍历链表并根据type进行对应处理,也就是处理dispatcher中的任务。
// 处理任务队列中的任务
int eventLoopProcessTask(struct EventLoop* evLoop) {...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);}...}...return 0;
}
  • 处理dispatcher中的任务 -- 添加 删除 修改
// 处理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);

 一、添加fdDispatcher的文件描述符检测集合中

把文件描述符fdchannel的对应关系存储到channelMap。这么做是为了什么?

  • dispatcher里边,还有dispatch函数指针,也就是dispatcher->dispatch(evLoop,timeout)。这个是一个检测函数,通过调用dipatch函数,就可以得到激活的文件描述符,得到了激活的文件描述符之后,需要通过这个文件描述符找到它所对应的channel
channelMap->list[fd] = channel; 

把文件描述符添加到dispatcher对应的文件描述符检测集合中

  • 首先从evLoop里边把dispatcher这个实例给取出来:evLoop->dispatcher,在dispatcher里边有一系列的函数指针,其中有一个叫做add。这个add就是把文件描述符添加到dispatcher对应的文件描述符检测集合中,函数指针add,指向的底层函数可能是不一样的,这个取决于我们选择的dispatcher模型,它有可能是poll,有可能是epoll,也有可能是select。选择的IO模型不一样,add这个函数指针指向的函数的处理动作也就不一样
evLoop->dispatcher->add(channel,evLoop); 

 (1)eventLoopAdd 

// 将任务队列中的任务添加到Dispatcher的文件描述符检测集合中
int eventLoopAdd(struct EventLoop* evLoop,struct Channel* channel) {int fd = channel->fd;// 取出文件描述符fdstruct ChannelMap* channelMap = evLoop->channelMap;// channelMap存储着channel和fd之间的对应关系// 需要判断channelMap里边是否有fd 和 channel对应的键值对(其中,文件描述符fd对应的就是数组的下标)if(fd >= channelMap->size) {// 没有足够的空间存储键值对 fd->channel ==> 扩容if(!makeMapRoom(channelMap,fd,sizeof(struct Channel*))) {return -1;}}// 找到fd对应的数组元素位置,并存储if(channelMap->list[fd] == NULL) {channelMap->list[fd] = channel;evLoop->dispatcher->add(channel,evLoop);} return 0;
}

1. 主题: 文件描述符与ChannelDispatcher中的交互

2. 重要信息:

  • Channel结构体:封装了文件描述符,并在其中存储了所需的数据
  • 添加文件描述符到Dispatcher:当有新文件描述符需要添加时,它会被放入Dispatcher的检测集合中
  • 文件描述符激活与处理:如果某个文件描述符在Dispatcher的检测集合中被激活,可以通过调用dispatch函数获取这个文件描述符,并进一步找到对应的Channel
  • 回调函数与事件处理:一旦找到对应的Channel,可以根据触发的事件调用在Channel结构体中注册的回调函数
  • ChannelMap结构体:用于存储文件描述符Channel之间的对应关系。它是一个数组,下标(即数组索引)对应文件描述符的值
  • 扩容ChannelMap:如果当前ChannelMap的容量不足,可以通过调用 makeMapRoom 函数进行扩容

3. 总结:详细介绍了如何通过Channel结构体和Dispatcher处理文件描述符,以及如何通过回调函数处理不同的事件。同时,还提到了如何使用和扩容ChannelMap结构体来存储文件描述符与Channel之间的对应关系

4. 思考与理解: 深入理解文件描述符、ChannelDispatcher之间的关系及其工作原理。 在实际编程中,考虑如何有效地使用和扩展ChannelMap结构体,以适应更多的文件描述符和事件处理需求。 考虑如何在代码中实现更清晰的事件处理逻辑,以提高代码的可读性和可维护性

总结:主要描述了如何通过文件描述符在channel中添加、激活和触发事件。其中,channelMap结构体用于存储文件描述符和channel的对应关系,而EventLoop结构体则用于存储channel和文件描述符的对应关系

核心观点 :

  • 文件描述符与channel的对应关系存储在channelMap中,通过数组索引对应文件描述符的值
  • 如果channelMap容量不足,需要调用函数进行扩容

二、从Dispatcher的文件描述符检测集合中删除fd

把任务队列里面的节点从dispatcher的检测集合中删除,调用dispatcher里边的remove函数

  • 如果我们要删除的这个文件描述符并不在channelMap中存储着,说明我们要操作的这个文件描述符并不在dispatcher的检核集合中。因为它在检测集合里边,在添加的时候就会把文件描述符fdchannel的映射关系也存储到channelMap里边去了。故只要它在检测集合里边,它肯定就在channelMap里边。如果它不在channelMap里边,那么它就肯定不在检测集合里边。如果它不在检测集合里边,就无需做任何事情,直接返回-1
  • 如果文件描述符fd在检测集合里,就从中把它删除

int eventLoopRemove(struct EventLoop* evLoop,struct Channel* channel) {int fd = channel->fd;struct ChannelMap* channelMap = evLoop->channelMap;if(fd >= channelMap->size) {return -1;}int ret = evLoop->dispatcher->remove(channel,evLoop);return ret;
}

三、修改Dispatcher的检测集合里边文件描述符事件的函数

当我们需要修改检测集合中的某个文件描述符事件时,首先需要判断该文件描述符是否在channelMap中。如果文件描述符存在,我们可以根据它获取一个非零的地址,这个地址实际上是channel实例的地址

  • 如果获取的地址为,说明传入的文件描述符对应的channel有问题;
  • 如果不为空,我们可以通过evLoop实例调用其函数指针modify

int eventLoopModify(struct EventLoop* evLoop,struct Channel* channel) {int fd = channel->fd;struct ChannelMap* channelMap = evLoop->channelMap;if(fd >= channelMap->size || channelMap->list[fd] == NULL) {return -1;}int ret = evLoop->dispatcher->modify(channel,evLoop);return ret;
}

四、释放channel

// 释放channel
int destroyChannel(struct EventLoop* evLoop,struct Channel* channel);

从检测集合中删除文件描述符后,对应的channel实例没有用了,因此需要释放它。在释放channel之前,我们需要关闭文件描述符,因为不再需要检测它的事件。此外,由于channel本身是一个指向堆内存的指针,我们需要释放这块堆内存。 

// 释放channel
int destroyChannel(struct EventLoop* evLoop,struct Channel* channel) {// 删除 channel 和 fd 的对应关系evLoop->channelMap->list[channel->fd] = NULL;// 关闭 fdclose(channel->fd);// 释放 channel 内存free(channel);return 0;
}

这篇关于基于多反应堆的高并发服务器【C/C++/Reactor】(中)添加 删除 修改 释放的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/569398

相关文章

VScode连接远程Linux服务器环境配置图文教程

《VScode连接远程Linux服务器环境配置图文教程》:本文主要介绍如何安装和配置VSCode,包括安装步骤、环境配置(如汉化包、远程SSH连接)、语言包安装(如C/C++插件)等,文中给出了详... 目录一、安装vscode二、环境配置1.中文汉化包2.安装remote-ssh,用于远程连接2.1安装2

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

C#实现添加/替换/提取或删除Excel中的图片

《C#实现添加/替换/提取或删除Excel中的图片》在Excel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更加美观,下面我们来看看如何在C#中实现添加/替换/提取或删除E... 在Excandroidel中插入与数据相关的图片,能将关键数据或信息以更直观的方式呈现出来,使文档更

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

Git中恢复已删除分支的几种方法

《Git中恢复已删除分支的几种方法》:本文主要介绍在Git中恢复已删除分支的几种方法,包括查找提交记录、恢复分支、推送恢复的分支等步骤,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录1. 恢复本地删除的分支场景方法2. 恢复远程删除的分支场景方法3. 恢复未推送的本地删除分支场景方法4. 恢复

Window Server创建2台服务器的故障转移群集的图文教程

《WindowServer创建2台服务器的故障转移群集的图文教程》本文主要介绍了在WindowsServer系统上创建一个包含两台成员服务器的故障转移群集,文中通过图文示例介绍的非常详细,对大家的... 目录一、 准备条件二、在ServerB安装故障转移群集三、在ServerC安装故障转移群集,操作与Ser

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

Oracle数据库使用 listagg去重删除重复数据的方法汇总

《Oracle数据库使用listagg去重删除重复数据的方法汇总》文章介绍了在Oracle数据库中使用LISTAGG和XMLAGG函数进行字符串聚合并去重的方法,包括去重聚合、使用XML解析和CLO... 目录案例表第一种:使用wm_concat() + distinct去重聚合第二种:使用listagg,

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC