资讯动态

【Linux】进程的终止、等待

发布时间:2026/10/5 2:28:38 来源:尧图企业网站定制
目录退出码用 strerror 查看退出码描述exit和_exit进程等待概念进程等待的必要性进程等待的方式——两个接口wait函数waitpid函数获取子进程status扩展父进程获取子进程的信息流程waitpid的方法option的非阻塞理解写代码的时候编译后一般会有三种结果程序正常且结果正确程序正常但结果错误程序异常错误示例#include stdio.h int main() { printf(hello world\n); return 0; }写代码的时候通常会在main函数的最后面写一个return 0,这个表示的是程序的执行情况——无异常。如果返回值非0且不同代表他的错误情况不同。其中这个返回值就是退出码这个返回值给谁的——父进程一般是bash写到take_struct内部的父进程要得到子进程的运行情况是从子进程的PCB里面读打印最近一个进程的进程退出码echo $?退出码Linux常见的退出码退出码含义典型场景0成功执行命令正常完成1通用错误一般性错误2命令或参数使用不当参数错误、用法错误126权限被拒绝文件没有执行权限127未找到命令命令不存在或 PATH 错误128n被信号终止n 是信号编号130被 SIGINT 终止CtrlC 中断143被 SIGTERM 终止默认终止信号255退出码超出范围重新计算取模规则规则说明0成功非 0失败范围0~255超过 255 会取模查看echo $?用 strerror 查看退出码描述#include stdio.h #include string.h int main() { for (int i 0; i 10; i) { printf(退出码 %d: %s\n, i, strerror(i)); } return 0; }如果在shell上面想把错误信息打印出来#include stdio.h #include string.h #include errno.h int main() { FILE *fp fopen(notexist.txt, r); if (fp NULL) { printf(错误%s\n, strerror(errno)); } return 0; }exit和_exitexit正常结束进程释放资源把退出码告诉父进程。#include stdio.h #include stdlib.h int main() { printf(hello); // 注意没有 \n exit(0); return 0; } //hello_exit#include stdio.h #include unistd.h int main() { printf(hello); // 注意没有 \n _exit(0); return 0; } //什么都不打印_exit不刷新缓冲区hello留在缓冲区里进程直接退出数据丢失。exit_exit刷新缓冲区会不会执行清理函数会不会关闭流会不会谁提供C 标准库系统调用头文件stdlib.hunistd.h缓冲区内存区域临时存放数据如果遇到\n程序结束、缓冲区满才会输出数据。其中这里面的缓存区是在C语言的库里面的缓存区不是操作系统的。从系统层级角度——exit的底层是封装了_exit_exit是系统调用的exit是库函数的我们知道只有操作系统能管理进程你要结束进程的话就要必须通过操作系统的接口——_exitexit才能做到进一步的结束进程。进程等待概念父进程等子进程退出然后回收子进程的资源、获取子进程的退出结果。进程等待的必要性1、回收子进程资源防止僵尸进程2、获取子进程的退出结果成功还是失败、退出码是多少3、保证父进程和子进程的时序父进程等子进程先退出进程等待的方式——两个接口wait函数#include sys/types.h #include sys/wait.h pid_t wait(int *status);status参数输出型参数记录子进程退出信息传NULL表示不关心退出状态返回值含义 0成功返回被回收子进程的 PID-1失败没有子进程waitpid函数#include sys/types.h #include sys/wait.h pid_t waitpid(pid_t pid, int *status, int options);参数说明pid指定等待哪个子进程status输出型参数记录退出信息options选项0 表示阻塞WNOHANG表示非阻塞Pid的值值含义-1等待任意子进程等价于wait 0等待指定 PID 的子进程0等待同组的任意子进程 -1等待指定进程组的任意子进程options的取值值含义0阻塞等待WNOHANG非阻塞没有子进程退出就立即返回 0返回值返回值含义 0成功返回被回收子进程的 PID0设置了WNOHANG但没有子进程退出-1失败#include stdio.h #include stdlib.h #include unistd.h #include sys/wait.h int main() { pid_t id fork(); if (id 0) { printf(child: pid%d\n, getpid()); sleep(3); exit(10); } else { int status; pid_t ret waitpid(id, status, 0); // 等待指定子进程 printf(parent: waitpid returned %d\n, ret); if (WIFEXITED(status)) { printf(child exit code: %d\n, WEXITSTATUS(status)); } } return 0; }获取子进程statusstatus要看成一个位图来看待。status是一个32 位整数但只有低 16 位有意义。分两种情况正常终止高 8 位是退出码低 8 位是 0被信号终止低 7 位是信号编号第 7 位是 core dump 标志——这样退出码没有意义了获取退出码——用到了位操作#include stdio.h #include errno.h #include string.h #include stdlib.h #include unistd.h #include sys/types.h #include sys/wait.h int exitcode 0; int main() { pid_t id fork(); if (id 0) { // 子进程 int cnt 3; while (cnt) { printf(我是一个子进程, pid : %d, ppid : %d\n, getpid(), getppid()); sleep(1); cnt--; } exitcode 10; exit(10); } // 父进程 // 1. 子进程退出 // 2. 子进程没退出呢 // pid_t rid wait(NULL); int status 0; pid_t rid waitpid(id, status, 0); if (rid 0) { printf(wait success, rid: %d, exit code: %d\n, rid, (status 8) 0xFF); // 获取退出码 } else { printf(wait failed: %d: %s\n, errno, strerror(errno)); } }信号编号这里有熟悉的kill -9 pid,其中这里的9就是杀掉进程的信号编号。——SIGKILL就是宏。简单提一下。扩展父进程获取子进程的信息流程由于进程具有独立性父进程不可能直接得到子进程的退出信息——退出码、状态等。因此要通过系统调用——那么系统调用的得到的子进程的信息又从哪里来——take_struct1. 子进程退出 - 调用 exit(10) - OS 把 exit_code 10、exit_signal 0 存入子进程的 task_struct - 子进程变成僵尸Z2. 父进程调用 waitpid(status) - OS 检查子进程是否已退出 - 已退出 → 从子进程的 task_struct 读 exit_code 和 exit_signal - 把 exit_code 左移 8 位加上 exit_signal - 得到 status 10 8 0x0A00 - 把 status 写入父进程的变量 - 释放子进程的 task_struct - waitpid 返回子进程 PID3. 父进程解析 status - WIFEXITED(status) → 真正常退出 - WEXITSTATUS(status) → 10take_struct的信息struct task_struct { pid_t pid; // 进程 ID long state; // 进程状态Z 表示僵尸 int exit_code; // 退出码 int exit_signal; // 终止信号 // ... };waitpid的方法pid_ t waitpid(pid_t pid, int *status, int options); 返回值 当正常返回的时候waitpid返回收集到的⼦进程的进程ID 如果设置了选项WNOHANG,⽽调⽤中waitpid发现没有已退出的⼦进程可收集,则返回0 如果调⽤中出错,则返回-1,这时errno会被设置成相应的值以指⽰错误所在 参数 pid Pid-1,等待任⼀个⼦进程。与wait等效。 Pid0.等待其进程ID与pid相等的⼦进程。 status: 输出型参数 WIFEXITED(status): 若为正常终⽌⼦进程返回的状态则为真。查看进程 是否是正常退出 WEXITSTATUS(status): 若WIFEXITED⾮零提取⼦进程退出码。查看进程 的退出码 options:默认为0表⽰阻塞等待 WNOHANG: 若pid指定的⼦进程没有结束则waitpid()函数返回0不予以等 待。若正常结束则返回该⼦进程的ID。如果子进程已经退出调用wait/waitpid时wait/waitpid会立即返回并且释放资源获得子进程退出信息。如果在任意时刻调用wait/waitpid子进程存在且正常运行则进程可能阻塞。如果不存在该子进程则立即出错返回option的非阻塞理解int status; waitpid(-1, status, 0); // 0 表示阻塞方式一句话阻塞父进程暂停一直等子进程退出非阻塞父进程不暂停问一下就走过会儿再来问#include stdio.h #include stdlib.h #include unistd.h #include sys/wait.h int main() { pid_t id fork(); if (id 0) { // 子进程 printf(child: 我在干活\n); sleep(5); exit(10); } else { // 父进程 int status; while (1) { pid_t ret waitpid(id, status, WNOHANG); if (ret 0) { // 子进程退出了 printf(child exit code: %d\n, WEXITSTATUS(status)); break; } else if (ret 0) { // 子进程还在运行 printf(parent: 子进程还在跑我先干点别的\n); sleep(1); } } } return 0; }

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑