基于多反应堆的高并发服务器【C/C++/Reactor】(中)主线程给子线程添加任务以及如何处理该任务

在看此篇文章,建议先看我的往期文章: 

基于多反应堆的高并发服务器【C/C++/Reactor】(中)在EventLoop的任务队列中添加新任务-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/135346492?spm=1001.2014.3001.5501一、了解socketpair函数(CodeGeex生成)

Linux 中的 socketpair 函数用于创建一个双向的 socket 连接,通常用于父子进程之间的通信。在上述代码中,socketpair 函数用于初始化一个事件循环(EventLoop)对象,并为其分配一个 socket pair,用于接收来自子进程的数据。

socketpair 函数的原型为:

#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);

其中,family 参数指定套接字家族(如 AF_UNIXAF_INET),type 参数指定套接字类型(如 SOCK_STREAM SOCK_DGRAM),protocol 参数指定套接字协议(如 0),sv[2] 参数指向一个整数数组,用于存储创建的文件描述符对。

如果 socketpair 函数返回 0,则表示创建成功,如果返回 -1,则表示创建失败

二、socketpair 初始化

socketpair 是一个在Unix-like系统上创建套接字对的函数。它创建的两个套接字描述符(socketpair[0] socketpair[1])可以用于进程间通信(IPC)socketpair[1] 的作用如下:

  1. 双向通信socketpair[1] 可以用于与 socketpair[0] 进行全双工通信。这意味着,每一个套接字既可以读也可以写。例如,可以往 socketpair[0] 中写,从 socketpair[1] 中读;或者从socketpair[1] 中写,从 socketpair[0] 中读。
  2. 阻塞与非阻塞:如果往一个套接字(如 socketpair[0] )中写入后,再从该套接字读时会阻塞,只能在另一个套接字(如 socketpair[1] )上读成功。
  3. 进程间通信:读、写操作可以位于同一个进程,也可以分别位于不同的进程,如父子进程。如果是父子进程时,一般会功能分离,一个进程用来读,一个用来写。因为文件描述符socketpair[0] socketpair[1]是进程共享的,所以读的进程要关闭写描述符,反之,写的进程关闭读描述符。总的来说,socketpair[1] 在进程间通信中扮演着重要的角色,它使得两个进程可以通过套接字进行数据交换。

>>(1)主线程唤醒子线程 

  • Channel.h 
// 定义函数指针
typedef int(*handleFunc)(void* arg);struct Channel {// 文件描述符int fd;// 事件int events;// 回调函数handleFunc readCallback;// 读回调handleFunc writeCallback;// 写回调// 回调函数的参数void* arg;
};
  • Channel.c 
#include "Channel.h"struct Channel* channelInit(int fd, int events, handleFunc readFunc, handleFunc writeFunc, void* arg) {struct Channel* channel = (struct Channel*)malloc(sizeof(struct Channel));channel->fd = fd;channel->events = events;channel->readFunc = readFunc;channel->writeFunc = writeFunc;channel->arg = arg;return channel;
}
  • EventLoop.c

evLoop->socketPair[1]作了封装,得到了一个channel

struct Channel* channel = channelInit(evLoop->socketPair[1],ReadEvent, readLocalMessage,NULL,evLoop);

那么对于evLoop->socketpair[1]这个文件描述符什么时候就能被被激活呢?

  • 通过一个写数据的函数,往socketPair[0]里边写数据的时候,通过socketPair[1]就能够接收到数据,此时这个socketPair[1]就被激活了,就去调用其读事件。
  • 这么做的原因是:底层的dispatcherpoll、epoll_wait或select,它们有可能是阻塞的,比如说它们检测的集合里边有文件描述符没有处于激活状态,我们往这个检测集合里安插了一个内线,通过socketPair[0]去写数据,只要一写数据,对应的poll、epoll_wait或select能够检测到socketPair[1]的读事件被激活了。
  • 如果检测到socketPair[1]的读事件被激活了,那么poll、epoll_wait或select阻塞函数就直接被解除阻塞了。它们解除阻塞了,子线程就能够正常工作了。子线程能够正常工作,子线程就能够处理任务队列里边的任务,通过主线程往evLoop->socketPair[0]发送数据(写数据),void taskWakeup(struct EventLoop* evLoop);
// 写数据
void taskWakeup(struct EventLoop* evLoop) {const char* msg = "我是要成为海贼王的男人!";write(evLoop->socketPair[0],msg,strlen(msg));
}

此时socketPair[1]被激活了,它所对应的读回调就会被调用。这样就能解除子线程的阻塞,让它去处理任务队列里边的任务

// 读数据 读事件回调函数在执行时需要指定参数
int readLocalMessage(void* arg) {struct EventLoop* evLoop = (struct EventLoop*)arg;char buffer[256];int ret = read(evLoop->socketPair[1],buffer,sizeof(buffer));if (ret > 0) {printf("read msg: %s\n",buffer);}return 0;
}

>>(2)channel 添加到任务队列

第一步:channel 添加到任务队列 通过调用eventLoopAddTask(evLoop,channel,ADD);添加到了任务队列 

// channel 添加到任务队列
eventLoopAddTask(evLoop, channel,ADD);

第二步:遍历任务队列,从中取出每一个节点,根据节点里边的类型对这个节点做操作(待续~,在后续的文章中会讲到eventLoopProcessTask这个函数),若是type为添加(ADD),那么就把任务节点添加到任务队列中去

故在下面的这篇文章的基础上,增加一些代码内容:

基于多反应堆的高并发服务器【C/C++/Reactor】(中)EventLoop初始化和启动_一个eventloop 可以有多少个连接-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/135225734?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22135225734%22%2C%22source%22%3A%22weixin_41987016%22%7DEventLoop.h中添加 int sockPair[2];表示存储本地通信的fd,通过socketpair初始化

struct EventLoop{bool isQuit;// 开关struct Dispatcher* dispatcher;void* dispatcherData;// 任务队列struct ChannelElement* head;struct ChannelElement* tail;// 用于存储channel的mapstruct ChannelMap* channelMap;// 线程ID,Name,mutexpthread_t threadID;char threadName[32];pthread_mutex_t mutex;int socketPair[2]; //存储本地通信的fd 通过socketpair初始化
};

EventLoop.c中续写 

struct EventLoop* eventLoopInitEx(const char* threadName) {struct EventLoop* evLoop = (struct EventLoop*)malloc(sizeof(struct EventLoop));evLoop->isQuit = false; // 没有运行evLoop->dispatcher = &EpollDispatcher;evLoop->dispatcherData = evLoop->dispatcher->init(); // 任务队列(链表)evLoop->head = evLoop->tail = NULL;// 用于存储channel的mapevLoop->channelMap = channelMapInit(128);evLoop->threadId = pthread_self(); // 当前线程IDstrcpy(evLoop->threadName,threadName == NULL ? "MainThread" : threadName); // 线程的名字pthread_mutex_init(&evLoop->mutex, NULL); // 已续写int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, evLoop->socketPair);if(ret == -1) {perror("socketpair");exit(0);}// 指定规则:evLoop->socketPair[0] 发送数据,evLoop->socketPair[1]接收数据struct Channel* channel = channelInit(evLoop->socketPair[1],ReadEvent, readLocalMessage,NULL,evLoop);// channel 添加到任务队列eventLoopAddTask(evLoop, channel,ADD);return evLoop;
}

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

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

相关文章

Raft Lab3A

Lab3 需要在 Raft 层上实现一个 fault-tolerant key-value service&#xff0c;满足强一致性&#xff0c;也就是线性一致性 (Linearizable Consistency)。线性一致性保证整个系统看起来好像只有一个副本&#xff0c;其中所有的操作都是原子性的。简单地说&#xff0c;线性一致性…

什么是发作性睡病?

发作性睡病是一种罕见的神经系统疾病&#xff0c;主要症状表现为无法控制的白天嗜睡。此病在全球范围内的发病率约为0.02-0.18%&#xff0c;通常在儿童或青少年时期发病。 首先&#xff0c;我们来了解一下发作性睡病的典型症状。患者在清醒状态下&#xff0c;如上课、开会或开…

swift ——多行文字前面内容省略

首先来说一说ios中的 lineBreakModelineBreakMode : 设置文字过长时的显示截断样式 可选值如下 byWordWrapping &#xff1a; 以单词为单位换行&#xff0c;以单词为单位截断。byCharWrapping &#xff1a;以字符为单位换行&#xff0c;以字符为单位截断。byClipping &#x…

C+语言的新特性

总是期待学习别人做好了的东西&#xff0c;是否也是一种懒惰呢&#xff1f; C语言是一门想象中的语言&#xff0c;它介于C和C之间。新的研究表明&#xff0c;C语言不支持某些特性&#xff0c;而C过于复杂。于是&#xff0c;便有了C语言&#xff0c;它的新特性如下&#xff1a; …

【Proteus仿真】【Arduino单片机】太阳能追光系统设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用LCD1602液晶、光敏传感器、ADC模块、按键模块、28BYJ48步进电机驱动模块、直流电机模块等。 主要功能&#xff1a; 系统运行后&#xff0c;L…

QGIS009:QGIS常用插件、GDAL和GRASS GIS常用工具

摘要:本文介绍QGIS支持的数据格式、QGIS常用插件以及GDAL和GRASS GIS模块常用工具。 一、QGIS支持的数据格式 1、矢量数据格式 1.1文件格式 ESRI Shapefile(SHP):ESRI公司开发的一种空间矢量数据文件格式,是最为常用的矢量数据格式之一,支持点、线、面等要素类型。GeoJ…

vue 的实例生命周期

Vue.js 的实例生命周期指的是 Vue 实例在创建、更新和销毁过程中的一系列事件和钩子函数&#xff0c;允许在不同阶段执行自定义操作。Vue 实例的生命周期可以分为以下阶段&#xff1a; 创建&#xff08;Creation&#xff09;&#xff1a; beforeCreate&#xff1a;在实例初始化…

DS|哈夫曼编码及应用

题目一&#xff1a;DS树 -- 赫夫曼树的构建与编码 题目描述&#xff1a; 给定n个权值&#xff0c;根据这些权值构造huffman树&#xff0c;并进行huffman编码 注意数组访问是从位置1开始 要求&#xff1a;赫夫曼的构建中&#xff0c;默认左孩子权值不大于右孩子权值 输入要…

淘宝商品详情API接口(item_get-获得淘宝商品详情)主图,属性,sku,价格,搜索商品列表

淘宝开放平台提供了API接口&#xff0c;允许开发者获取淘宝商品的相关信息。为了获取商品详情&#xff0c;您可以使用 item_get API接口。以下是如何使用此API接口来获取商品的主图、属性、SKU、价格以及搜索商品列表的简要说明&#xff1a; 公共参数 名称类型必须描述keyStr…

PromptCast:基于提示学习的时序预测模型!

目前时序预测的SOTA模型大多基于Transformer架构&#xff0c;以数值序列为输入&#xff0c;如下图的上半部分所示&#xff0c;通过多重编码融合历史数据信息&#xff0c;预测未来一定窗口内的序列数值。 受到大语言模型提示工程技术的启发&#xff0c;文章提出了一种时序预测新…

Redis小计(3)

目录 redis为什么是单线程模型和为什么不推荐使用"keys *"指令 redis为什么是单线程模型和为什么不推荐使用"keys *"指令 单线程模型可以避免线程安全问题&#xff0c;即并发访问导致的数据冲突。当大量客户端发来请求时&#xff0c;redis服务器只能一个一…

排序之冒泡排序

冒泡排序是一种简单的排序算法&#xff0c;它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排序完成。 思路&#xff1a; 左边大于右边交…

Mobileperf:优化移动应用性能的关键工具

引言&#xff1a; 随着移动设备的普及和功能的不断增强&#xff0c;移动应用在人们的日常生活中扮演着越来越重要的角色。然而&#xff0c;由于移动设备资源有限&#xff0c;如处理器、内存和电池等&#xff0c;移动应用的性能问题也日益突出。为了提高用户体验和满足用户需求&…

单机部署Rancher

上次已经安装完毕了k8s了&#xff0c;但是想要界面化的管理&#xff0c;离不开界面工具&#xff0c;首推就是rancher&#xff0c;本文介绍安装rancher的安装&#xff0c;也可以将之前安装的k8s管理起来。 已经安装完毕docker和docker-ce的可以直接从第三部分开始。 一、基础准…

【数据库原理】(10)数据定义功能

SQL 数据定义功能包括定义模式、定义表、定义索引和定义视图,其语句如表所示。 一.创建、删除模式 1.创建模式 (Create Schema) 用途&#xff1a;创建模式是为了在数据库中定义一个新的命名空间&#xff0c;它可以包含多个数据库对象。 语法&#xff1a; CREATE SCHEMA &…

json.stringify()详解

json.stringify()详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一同深入探讨在JavaScript中常用的JSON处理方法——JSON.stringify()&…

数据库期末重点

第一章&#xff1a; 1.数据库发展的三个阶段 第一代数据库系统、第二代数据库系统、新一代数据库系统 2.数据库系统发展的三个里程碑 IMS系统、DBTG报告、关系数据库系统 3.数据管理技术三个阶段 人工管理阶段(40年代中-50年代中) 文件系统阶段(50年代末-60年代中) 数据…

选择排序!!!基础排序详解 C语言版

目录 1.什么是选择排序 2.选择排序源代码 3.优化代码 1.什么是选择排序 这是一个选择排序的流程图&#xff0c;其实很简单&#xff0c;就是每次挑选数字中最小的作为第一个 &#xff0c;直到整个数据有序就结束了 顾名思义&#xff0c;选择&#xff0c;那就是选取&#xff0c…

打造私域流量的知识付费小程序saas租户平台

当今信息爆炸的时代&#xff0c;知识管理已经成为了每个人必须面对的问题。然而&#xff0c;市面上的知识付费平台大多数都是通用的&#xff0c;无法满足个性化需求。 因此&#xff0c;明理信息科技提供了一款专属定制的适合个人的知识付费平台。核心产品能力如下&#xff1a;…

Visual Studio Code可以做到这一点:提示和技巧:Build 2018

Visual Studio Code火了。每个人都喜欢这个意想不到的文本编辑器&#xff0c;而且理由很充分&#xff1a;它可以做很多事情。它可以动态编译JavaScript模板&#xff0c;内联执行JavaScript&#xff0c;管理Mongo DB实例等等&#xff01;在这个部分&#xff0c;我们将看到Visual…