第 31 / 120 课 · 进程、线程与调度。返回课程合集。
机制与资源关系
子进程退出后保留供父进程读取的状态,父进程未 wait 会出现僵尸。僵尸通常不再执行代码,但会占据进程表资源。孤儿进程则描述父子关系变化,与僵尸不是同义词。
实际用法与观察入口
以下是操作说明;先确认执行环境、工具帮助和目标对象。设备名、PID、地址及项目名示例需要按实际替换,不能将整段命令当通用板端脚本执行。
|
输出解读与排查顺序
Z 状态不能靠再次 kill 子进程回收,应修复父进程回收逻辑。容器中的 PID 1 或 subreaper 也影响接管关系;不要默认所有孤儿都由宿主机 PID 1 直接接管。
情境推演
程序每次启动子工具都不回收,长期出现越来越多 Z 状态。修复父进程的 wait 逻辑,并处理所有退出分支。给僵尸发 SIGKILL 不会替父进程读取退出状态。
练习与参考分析
查看本课实验中“子进程已退出→父进程 wait”的状态转换。参考结论:所有成功创建的子进程都应有回收路径,包括业务失败和提前退出分支。
独立实验包
主机 Linux 的有界 C 实验;不访问真实外设,不代表板端时序或性能。 默认入口、源文件和实际运行记录都在下载包中。
实验:僵尸进程与子进程回收
查看完整代码:main.c
int main(void) {
pid_t child = fork(); CHECK(child >= 0);
if (child == 0) _exit(3);
siginfo_t info = {0};
CHECK(waitid(P_PID, (id_t)child, &info, WEXITED | WNOWAIT) == 0);
CHECK(info.si_pid == child && info.si_code == CLD_EXITED && info.si_status == 3);
puts("child exited; WNOWAIT deliberately leaves status available");
int status = 0; CHECK(waitpid(child, &status, 0) == child);
CHECK(WIFEXITED(status) && WEXITSTATUS(status) == 3);
errno = 0; CHECK(waitpid(child, &status, WNOHANG) == -1 && errno == ECHILD);
puts("reaped child; a second wait reports ECHILD");
return 0;
}
在项目根目录执行;下载包解压后,在解压目录执行 sh run.sh。
cd 'content/posts/驱动、bootloader、文件系统/嵌入式Linux系统工程/031-僵尸进程与子进程回收/code' && sh run.sh
官方资料与版本边界
内核、工具和厂商 BSP 的支持范围需分别核对。参考资料可能对应较新版本;不要据此推定旧 BSP 支持所有接口。