ev_loop_fork函数

 libev监视器介绍:libev监视器用法-CSDN博客

libev loop对象介绍:loop对象-CSDN博客

libev ev_loop_fork函数介绍:ev_loop_fork函数-CSDN博客

libev API吐血整理:https://download.csdn.net/download/qq_39466755/90794251?spm=1001.2014.3001.5503

用于解决fork函数导致子进程集成的fd集合失效问题

#include <stdio.h>
#include <unistd.h>
#include <sys/event.h>
#include <fcntl.h>void child_process(int kq) {printf("Child: Attempting to use inherited kqueue...\n");struct kevent events[1];int n = kevent(kq, NULL, 0, events, 1, NULL); // 无超时等待printf("Child: kevent returned %d events (expected: 1)\n", n);
}int main() {int kq = kqueue();int pipe_fd[2];pipe(pipe_fd);// 监控管道读端struct kevent ev;EV_SET(&ev, pipe_fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL);kevent(kq, &ev, 1, NULL, 0, NULL);// 触发事件write(pipe_fd[1], "test", 5);pid_t pid = fork();if (pid == 0) {child_process(kq); // 子进程直接使用继承的 kqueue_exit(0);} else {struct kevent events[1];int n = kevent(kq, NULL, 0, events, 1, NULL);printf("Parent: kevent returned %d events\n", n);}return 0;
}

运行结果

Child: Attempting to use inherited kqueue...
Child: kevent returned 0 events (expected: 1)  # 子进程事件丢失!
Parent: kevent returned 1 events               # 父进程正常

修改代码子进程可以正常接收父进程的fd集合

#include <ev.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>// 管道读端回调
static void pipe_cb(struct ev_loop *loop, ev_io *w, int revents) {char buf[256];ssize_t n = read(w->fd, buf, sizeof(buf));printf("[%s] Received data: %.*s\n", getpid() == getppid() ? "Parent" : "Child", (int)n, buf);
}int main() {// 忽略 SIGPIPE(防止写入关闭的管道导致进程退出)signal(SIGPIPE, SIG_IGN);struct ev_loop *loop = EV_DEFAULT;int pipe_fd[2];pipe(pipe_fd);// 监控管道读端ev_io pipe_watcher;ev_io_init(&pipe_watcher, pipe_cb, pipe_fd[0], EV_READ);ev_io_start(loop, &pipe_watcher);// 写入数据(触发事件)write(pipe_fd[1], "hello", 6);pid_t pid = fork();if (pid == 0) {// ---------- 关键修复 ----------ev_loop_fork(loop);  // 重置内核状态// ------------------------------printf("Child: Started event loop\n");ev_run(loop, 0);  // 子进程现在能正常接收事件_exit(0);} else {printf("Parent: Started event loop\n");ev_run(loop, 0);}return 0;
}

运行结果

Parent: Started event loop
[Parent] Received data: hello  # 父进程正常接收
Child: Started event loop
[Child] Received data: hello   # 子进程修复后也能接收

结合libev接口,父子进程共享循环时的正确用法

struct ev_loop *loop = EV_DEFAULT;
ev_io parent_watcher;
ev_io_init(&parent_watcher, parent_cb, pipe_fd[0], EV_READ);
ev_io_start(loop, &parent_watcher);pid_t pid = fork();
if (pid == 0) {// 子进程ev_loop_fork(loop);  // 先重置后端// 添加子进程独有的监视器ev_io child_watcher;ev_io_init(&child_watcher, child_cb, another_fd, EV_WRITE);ev_io_start(loop, &child_watcher);ev_run(loop, 0);  // 现在能正确处理父/子监视器的事件
} else {// 父进程继续原逻辑ev_run(loop, 0);
}

代码解析:

        libev 使用底层机制(如 epoll/kqueue)来监听文件描述符。当调用 fork() 时,子进程会继承父进程的 epoll 实例,但该实例可能已失效(内核状态与用户态不一致)。ev_loop_fork() 会重建后端(如重新创建 epoll 实例),确保事件循环在子进程中能正常工作。因为struct ev_loop *loop = EV_DEFAULT;已经创建了底层的事件监听机制(如 epoll、kqueue 或 select 等,具体取决于系统支持)。

        即使子进程不直接使用 pipe_fd[0],事件循环本身仍需正确的后端支持。

        虽然子进程没有主动使用 parent_watcher(监视 pipe_fd[0]),但该监视器仍存在于 loop 中(因为它是父进程注册的)。未重置的事件循环可能会错误地尝试处理这些继承的监视器,导致未定义行为。

        一般情况下都是搭配libev开源库的API函数(ev_fork_init,ev_fork_start等)一起使用:

#include <ev.h>
#include <unistd.h>
#include <stdio.h>// fork 回调函数
void fork_cb(EV_P_ ev_fork *w, int revents) {printf("Child process (PID: %d) reinitializing event loop...\n", getpid());ev_loop_fork(EV_A); // 必须调用,重新初始化子进程的事件循环
}int main() {struct ev_loop *loop = EV_DEFAULT;struct ev_fork fork_watcher;// 初始化fork监视器ev_fork_init(&fork_watcher, fork_cb);ev_fork_start(loop, &fork_watcher); // 启动监视器printf("Parent process (PID: %d) started. Forking...\n", getpid());pid_t pid = fork();if (pid == 0) {// 子进程:ev_loop_fork已在回调中调用ev_run(loop, 0); // 子进程事件循环} else if (pid > 0) {// 父进程代码printf("Parent process continues (child PID: %d)\n", pid);sleep(2); // 模拟父进程工作} else {perror("fork failed");return 1;}return 0;
}

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

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

相关文章

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】金融风控分析案例-10.1 风险数据清洗与特征工程

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 PostgreSQL金融风控分析案例&#xff1a;风险数据清洗与特征工程实战一、案例背景&#xff1a;金融风控数据处理需求二、风险数据清洗实战&#xff08;一&#xff09;缺失值…

OpenCV 的 CUDA 模块中用于将一个多通道 GpuMat 图像拆分成多个单通道图像的函数split()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::split 是 OpenCV CUDA 模块中的一个函数&#xff0c;用于将一个多通道的 GpuMat 图像拆分成多个单通道的 GpuMat 图像。这个函数是 CP…

【WebRTC-13】是在哪,什么时候,创建编解码器?

Android-RTC系列软重启&#xff0c;改变以往细读源代码的方式 改为 带上实际问题分析代码。增加实用性&#xff0c;方便形成肌肉记忆。同时不分种类、不分难易程度&#xff0c;在线征集问题切入点。 问题&#xff1a;编解码器的关键实体类是什么&#xff1f;在哪里&什么时候…

c语言第一个小游戏:贪吃蛇小游戏03

我们为贪吃蛇的节点设置为一个结构体&#xff0c;构成贪吃蛇的身子的话我们使用链表&#xff0c;链表的每一个节点是一个结构体 显示贪吃蛇身子的一个节点 我们这边node就表示一个蛇的身体 就是一小节 输出结果如下 显示贪吃蛇完整身子 效果如下 代码实现 这个hasSnakeNode(…

架构思维:通用架构模式_系统监控的设计

文章目录 引言什么是监控三大常见监控类型1. 次数监控2. 性能监控3. 可用率监控 落地监控1. 服务入口2. 服务内部3. 服务依赖 监控时间间隔的取舍小结 引言 架构思维&#xff1a;通用架构模式_从设计到代码构建稳如磐石的系统 架构思维&#xff1a;通用架构模式_稳如老狗的SDK…

精益数据分析(46/126):深入剖析用户生成内容(UGC)商业模式

精益数据分析&#xff08;46/126&#xff09;&#xff1a;深入剖析用户生成内容&#xff08;UGC&#xff09;商业模式 在创业与数据分析的征程中&#xff0c;每一种商业模式都蕴含着独特的价值与挑战。今天&#xff0c;我们依旧怀揣着共同进步的信念&#xff0c;深入研读《精益…

QMK键盘固件中LED锁定指示灯的配置与使用详解(实操部分+拓展)

QMK键盘固件中LED锁定指示灯的配置与使用详解 大家好!今天就跟大家一起探索QMK固件中LED锁定指示灯的配置与使用。无论你是键盘DIY新手还是老司机,相信这篇教程都能帮你解锁新技能! 一、基础配置:定义LED引脚 在QMK固件中配置LED锁定指示灯非常简单,只需在config.h文件…

CVE体系若消亡将如何影响网络安全防御格局

CVE体系的核心价值与当前危机 由MITRE运营的通用漏洞披露&#xff08;CVE&#xff09;项目的重要性不容低估。25年来&#xff0c;它始终是网络安全专业人员理解和缓解安全漏洞的基准参照系。通过提供标准化的漏洞命名与分类方法&#xff0c;这套体系为防御者建立了理解、优先级…

一周学完计算机网络之三:1、数据链路层概述

简单的概述 数据链路层是计算机网络体系结构中的第二层&#xff0c;它在物理层提供的基本服务基础上&#xff0c;负责将数据从一个节点可靠地传输到相邻节点。可以将其想象成一个负责在两个相邻的网络设备之间进行数据 “搬运” 和 “整理” 的 “快递中转站”。 几个重要概念…

✨WordToCard使用分享✨

https://www.wordtocard.com 家人们&#xff0c;今天发现了一个超好用的工具——WordToCard&#xff01;&#x1f61c; 它可以把WordToCard文档转换成漂亮的知识卡片&#xff0c;学习笔记、知识整理和内容分享都变得超轻松&#xff5e;&#x1f917; 支持各种WordToCard语法…

扩展:React 项目执行 yarn eject 后的 package.json 变化详解及参数解析

扩展&#xff1a;React 项目执行 yarn eject 后的 package.json 变化详解及参数解析 什么是 yarn eject&#xff1f;React 项目执行 yarn eject 后的 package.json 变化详解1. 脚本部分 Scripts 被替换2. 新增构建依赖 dependencies&#xff08;部分&#xff09;3. 新增 Babel …

[Java实战]Spring Boot 整合 Redis(十八)

[Java实战]Spring Boot 整合 Redis&#xff08;十八&#xff09; 在现代的分布式应用开发中&#xff0c;Redis 作为一种高性能的键值存储数据库&#xff0c;被广泛用于缓存、消息队列、排行榜等多种场景。Spring Boot 提供了强大的支持&#xff0c;使得整合 Redis 变得非常简单…

【氮化镓】GaN在不同电子能量损失的SHI辐射下的损伤

该文的主要发现和结论如下: GaN的再结晶特性 :GaN在离子撞击区域具有较高的再结晶倾向,这导致其形成永久损伤的阈值较高。在所有研究的电子能量损失 regime 下,GaN都表现出这种倾向,但在电子能量损失增加时,其效率会降低,尤其是在材料发生解离并形成N₂气泡时。 能量损失…

R语言实战第5章(1)

第一部分&#xff1a;数学、统计和字符处理函数 数学和统计函数&#xff1a;R提供了丰富的数学和统计函数&#xff0c;用于执行各种计算和分析。这些函数可以帮助用户快速完成复杂的数学运算、统计分析等任务&#xff0c;例如计算均值、方差、相关系数、进行假设检验等。字符处…

k8s术语之Horizontal Pod Autoscaling

应用的资源使用率通常都有高峰和低谷的时候&#xff0c;如何削峰填谷&#xff0c;提高整体的整体资源利用率&#xff0c;让service中的Pod个数自动调整呢&#xff1f;Horizontal Pod Autoscaling:使pod水平自动缩放。这个Object也是最能体现kubernetes之于传统运维价值的地方&a…

Linux复习笔记(三) 网络服务配置(web)

遇到的问题&#xff0c;都有解决方案&#xff0c;希望我的博客能为你提供一点帮助。 二、网络服务配置 2.3 web服务配置 2.3.1通信基础&#xff1a;HTTP协议与C/S架构&#xff08;了解&#xff09; ​​HTTP协议的核心作用​​ Web服务基于HTTP/HTTPS协议实现客户端&#xff…

9.1.领域驱动设计

目录 一、领域驱动设计核心哲学 战略设计与战术设计的分野 • 战略设计&#xff1a;限界上下文&#xff08;Bounded Context&#xff09;与上下文映射&#xff08;Context Mapping&#xff09; • 战术设计&#xff1a;实体、值对象、聚合根、领域服务的构建原则 统一语言&am…

CSS Layer 详解

CSS Layer 详解 前言 最近在整理CSS知识体系时&#xff0c;发现Layer这个特性特别有意思。它就像是给样式规则提供了一个专属的「VIP通道」&#xff0c;让我们能更优雅地解决样式冲突问题。今天我就用最通俗的语言&#xff0c;带大家全面了解这个CSS新特性。 什么是CSS Laye…

【Dv3Admin】工具视图配置文件解析

在开发后台管理系统时,处理复杂的 CRUD 操作是常见的需求。Django Rest Framework(DRF)通过 ModelViewSet 提供了基础的增删改查功能,但在实际应用中,往往需要扩展更多的功能,如批量操作、权限控制、查询优化等。dvadmin/utils/viewset.py 模块通过继承并扩展 ModelViewS…

‌云原生CAE软件

‌云原生CAE软件‌是一种在设计和实现时就充分考虑了云环境特点的软件&#xff0c;能够充分利用云资源&#xff0c;实现高效、可扩展和灵活的仿真分析。 定义和特点 云原生CAE软件是一种在云端构建和运行的CAE&#xff08;Computer Aided Engineering&#xff0c;计算机辅助工…