
诊断服务启动一个工作进程,等它结束,再把状态交给上层。逻辑听起来只有一句话,但实现时有两个容易混淆的对象:操作系统提供的退出状态,以及业务约定的任务结果。
本文先用一个只会返回固定退出码的子进程,把结果收集过程缩到最小。不启动真实诊断工具,不运行模型,也不操作其他任务的进程。
等谁,比等多久先说清
fork 在父进程里返回子进程标识,在子进程里返回零。父进程保存这个标识,再用 waitpid(child, &status, 0) 等待自己创建的那个子进程。这里不使用“任意子进程”,避免把别的工作进程状态误认成当前任务。
status 是编码后的状态信息,不能直接当成退出码打印。应先检查退出方式,再使用对应宏解释它。这些接口与宏的含义已按 Linux wait(2) 手册核对。
直接运行的实验
下面代码保存为 wait.c,不依赖随文附件:
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
pid_t child=fork();
if(child<0){perror("fork");return 1;}
if(child==0)_exit(7);
int status;pid_t got;
do {got=waitpid(child,&status,0);} while(got<0 && errno==EINTR);
if(got<0){perror("waitpid");return 1;}
if(!WIFEXITED(status)){fputs("not normal exit\n",stderr);return 2;}
int code=WEXITSTATUS(status);
printf("normal exit code=%d\n",code);
return code==7 ? 0 : 3;
}
使用已有C编译器执行:
cc -Wall -Wextra -Werror wait.c -o wait
./wait
子进程调用 _exit(7)。这里的7是人为约定的测试值,不表示真实工具的某种错误。父进程检查 WIFEXITED(status) 后,才用 WEXITSTATUS(status) 提取值。
父程序最后返回零,表示本次实验拿到了预期值。不要把父程序的零和子进程的7混成同一个状态;它们来自两个不同的进程,也服务于不同的检查。
实际观察与未覆盖的部分
本次在macOS环境用现有编译器完成编译和执行,输出:
normal exit code=7
因此这次实际覆盖了创建自己的子进程、等待指定子进程、判断正常退出、提取固定退出码这条路径。代码包含遇到 EINTR 时重试的处理,但实验没有主动发送信号去触发该分支。信号终止分支也未执行,不应因为代码里考虑到了异常,就写成所有异常都已验证。
Linux手册说明,只有正常退出时才应使用 WEXITSTATUS;若是信号终止,则应先判断 WIFSIGNALED,再使用 WTERMSIG。退出码只携带有限的信息,不能用来塞进完整的业务结果。

图中“结合业务结果协议”是下一层工作。本文程序没有业务结果协议,只检查固定退出码,因此没有宣称某项诊断已经成功。
Linux上怎样对齐调用过程
若读者在已有Linux实验环境里装有 strace,可自行观察:
strace -f -e trace=process ./wait
本文制作时未执行这条命令,也没有为测试安装软件。-f 用于跟随子进程,进程相关过滤便于查看创建与等待过程。具体看到的底层调用名称可能受体系结构和C库实现影响,不能要求每个平台都出现字面上的 fork 或 waitpid 系统调用。
观察重点是:父进程创建子进程,子进程退出,父进程等待并得到状态。调度顺序可能让一些输出先后不同,不应只凭相邻两行就推断完整因果关系。
接到服务里,还缺哪些约定
第一,退出状态由谁负责收集。若一个模块调用等待接口,另一个模块也抢着收集同一子进程,就可能出现状态被提前取走的问题。工作进程的拥有者应明确。
第二,结果内容怎样传递。可以通过受控管道或约定文件传递结构化结果,但要单独校验完整性、任务标识和格式。进程返回零,结果文件仍可能缺失或属于上一次尝试。
第三,等待不能让整个服务失去响应。本文采用阻塞等待以展示语义;真实服务需要结合事件循环、专门管理线程或其他适合架构的机制处理等待与超时。改用非阻塞轮询时,还要正确区分“尚未结束”和“调用失败”。
第四,用户取消等待不等于子进程已经退出。后续的终止、收集和资源归还需要完成闭环。把进程状态和业务状态分别记录,才能避免界面显示结束、后台却仍有工作在跑。
最小实验的价值,就是先确定系统接口究竟告诉了我们什么。拿到退出状态只是结果处理的入口,业务结果仍要按自己的协议验证。
本文通过最小C程序演示如何正确使用waitpid收集子进程退出状态,强调区分操作系统退出码与业务结果的重要性。重点解析WIFEXITED/WEXITSTATUS宏的使用、指定子进程等待、信号终止处理、状态提取时机,并指出在服务集成中需补充的进程归属、结果传递、非阻塞等待及取消闭环等关键约定。
457

被折叠的 条评论
为什么被折叠?



