Linux pidfd_open 怎样稳定监控进程退出
如果监控器只保存一个 PID,进程结束后再按这个数字查询,遇到 PID 被系统重新分配时就可能把新进程误认成旧进程。Linux 的 pidfd_open() 提供了另一种对象模型:把已有进程映射为文件描述符,再把这个描述符交给 poll、epoll 或 waitid 观察生命周期。
这不是把 PID 变成“永远有效”的数字,而是让监控器持有一个指向进程对象的内核句柄。对需要等待进程退出、发送信号或接入统一事件循环的程序,这个边界比定时读取 /proc/ 更清楚。
为什么保存 PID 不足以表示一个进程
PID 是进程在某个时间点的数值标识,适合日志、命令行和人工排查,但它不是一个带生命周期的引用。监控器读取 PID 后如果暂存一段时间,原进程可能已经退出,系统随后把同一个数字分给另一个进程。此时“PID 仍存在”并不能推出“原目标仍存在”。
pidfd_open(pid, flags) 返回的是文件描述符。它可以被文件描述符等待机制观察,目标进程终止时,等待接口获得对应事件;文件描述符关闭后,监控器也明确释放了这份引用。这个模型把“找一个数字对应的进程”改成“等待一个已打开的对象句柄”。

用 pidfd_open 获取可等待的进程句柄
Linux 的 glibc 不一定提供同名包装函数,C 程序通常通过 syscall(SYS_pidfd_open, pid, flags) 调用系统调用。调用成功后要把返回值当成普通文件描述符管理:检查小于零的错误、在所有退出路径关闭它,并根据部署的内核版本决定是否使用扩展 flags。
#define _GNU_SOURCE #include#include #include #include #include #include static int open_pidfd(pid_t pid) { // flags 传 0 只请求一个指向目标进程的基础 pidfd。 return (int)syscall(SYS_pidfd_open, pid, 0U); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "用法:%s PID\\n", argv[0]); return 2; } errno = 0; pid_t pid = (pid_t)strtol(argv[1], NULL, 10); int pidfd = open_pidfd(pid); if (pidfd
示例重点是句柄的所有权,不是让每个检查脚本都复制一份逻辑。实际项目还应补上 、严格的数字解析和对目标 PID 范围的检查;这些属于输入处理,不能把任意命令行文本直接当成合法 PID。
把 pidfd 接入 poll 观察退出事件
拿到 pidfd 后,监控器可以把它放进 struct pollfd,请求 POLLIN 事件。目标进程终止并进入内核可观察状态后,poll 可能返回可读事件;这表示“生命周期状态发生了可等待变化”,并不等于从 pidfd 中能读取一段普通文本。pidfd 不是日志文件,read 不是读取退出原因的接口。
#include#include #include static int wait_process_exit(int pidfd) { struct pollfd watch = { .fd = pidfd, .events = POLLIN, .revents = 0, }; for (;;) { int ready = poll(&watch, 1, -1); if (ready

如果程序使用 epoll,思路相同:把 pidfd 注册为关注对象,收到 EPOLLIN 后进入退出处理。若还要取得子进程的等待信息,需要把 pidfd 与 waitid 的语义对应起来;不能把“收到事件”简单等同于“已经拿到了退出码”。
几个容易混淆的边界
| 场景 | 应该关注什么 | 不能直接推出什么 |
|---|---|---|
| 监控已有进程 | pidfd_open 能创建指向该任务的文件描述符 | 不能保证目标一直存活 |
poll 返回 POLLIN | 目标生命周期已出现可等待变化 | 不能从 pidfd 读取文本退出原因 |
使用 PIDFD_NONBLOCK | 等待接口可用非阻塞方式报告尚未结束 | 不等于所有上层等待逻辑自动非阻塞 |
| 监控线程而非进程 | 较新的内核可用 PIDFD_THREAD 表示特定线程 | 不能在旧内核上无条件启用该 flag |
| 进程退出后收尾 | 按所有权关闭 pidfd,必要时调用等待接口回收子进程 | 不能把关闭句柄当成回收僵尸进程 |
版本、资源和回退策略怎么定
pidfd_open 的基础能力来自较新的 Linux 内核;文档还列出了 PIDFD_NONBLOCK 与 PIDFD_THREAD 的版本边界。部署在多发行版环境时,不能只看编译机的头文件:启动时可以探测系统调用返回值,把 ENOSYS、EINVAL 或不支持的 flag 视为能力差异,并决定是否退回到明确标注风险的 PID 加复查方案。
同时要把 pidfd 数量纳入文件描述符预算。每个被长期监控的进程都可能占用一个描述符,达到进程级或系统级上限时会收到 EMFILE 或 ENFILE。因此,监控器应限制同时观察的目标数、在终止路径关闭描述符,并为异常分支保留可观测日志。
落地前的进程监控清单
- 先确认目标内核、C 库头文件和运行时是否支持基础
pidfd_open。 - 把 pidfd 当成有所有权的资源,明确创建、注册、事件处理和关闭的责任方。
- 将
POLLIN、EPOLLIN与waitid分成事件判断和状态回收两个动作。 - 为
ESRCH、EMFILE、ENFILE、EINTR和不支持 flag 设计分支。 - 如果必须兼容旧内核,明确回退方案的 PID 复用风险,不要宣称它与 pidfd 等价。
常见问题
pidfd_open 返回的文件描述符能直接 read 吗?
不能把它当作普通数据文件读取。它的价值在于作为进程对象的引用和等待对象,退出状态应通过相应的等待接口获取。
有了 pidfd 还需要保存 PID 吗?
日志、审计和与旧工具交互时仍然可以保存 PID,但涉及生命周期判断时应优先使用 pidfd,避免把一个后来复用的数字当成原进程。
pidfd 和 epoll 的关系是什么?
pidfd 是被监控的文件描述符,epoll 是等待多个描述符的机制。它们解决的层次不同,可以把多个 pidfd 与 socket、timerfd 等对象放进同一事件循环。
一句话总结:需要稳定观察进程生命周期时,先把进程转换为 pidfd,再把 pidfd 放进 poll 或 epoll;退出事件、等待回收、版本探测和文件描述符预算要分别设计。
Linux journalctl --rotate 怎样手动切换当前日志文件
- 上一篇
- Linux journalctl --rotate 怎样手动切换当前日志文件
- 下一篇
- Linux pressure stall information 怎样定位资源等待
-
- 文章 · linux | 12分钟前 | Linux · Linux systemd dump 服务管理器 systemd-analyze unit
- Linux systemd-analyze dump 怎样按 unit 过滤服务管理器状态
- 166浏览 收藏
-
- 文章 · linux | 30分钟前 | linux运维 · Linux systemd 服务限流 cgroup CPUQuota systemd.resource-control
- Linux systemd.resource-control 怎样限制 CPU 配额
- 148浏览 收藏
-
- 文章 · linux | 32分钟前 | 文件系统 · Linux 挂载树 mount_setattr 挂载属性 Mount API
- Linux mount_setattr 怎样批量调整挂载属性
- 432浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux proc_pid_fdinfo 怎样查看 epoll 监听项
- 227浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux rsync 怎样保留权限并排除缓存目录
- 308浏览 收藏
-
- 文章 · linux | 1小时前 |
- Linux nftables 怎样按接口限制入站端口
- 383浏览 收藏
-
- 文章 · linux | 1小时前 | Linux ·
- Linux journalctl --rotate 怎样手动切换当前日志文件
- 157浏览 收藏
-
- 文章 · linux | 1小时前 | Linux systemctl systemd.swap 交换文件 swapfile swap.target
- Linux systemd.swap 怎样配置交换文件单元
- 263浏览 收藏
-
- 文章 · linux | 20小时前 |
- Linux find -files0-from 怎样安全读取文件列表
- 391浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 857次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 862次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 938次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 919次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 747次使用
-
- Linux vmstat 如何分辨内存抖动与磁盘等待:si、so、wa 与复测顺序
- 2026-08-30 501浏览
-
- Linux搭建vsftpdFTP服务器教程
- 2026-04-30 501浏览
-
- Shell脚本安装教程:.sh一键安装指南
- 2026-03-16 501浏览
-
- Linux清空文件内容的几种方法
- 2025-12-01 501浏览
-
- Linux命令行下载文件技巧
- 2025-11-23 501浏览
