一、进程退出
-
退出场景
- 正常终止:代码执行完毕且结果符合预期(退出码为
0)。 - 异常终止:运行结果错误(退出码非
0)或进程被信号强制终止。(如SIGINT或SIGSEGV)。
- 正常终止:代码执行完毕且结果符合预期(退出码为
-
退出方法
- 正常退出方式:
return:从main函数返回,隐含调用exit函数。exit(int status):标准库函数,执行清理操作(如刷新缓冲区、调用atexit注册的函数)后终止进程。_exit(int status):系统调用,直接终止进程,不刷新缓冲区。
- 正常退出方式:
exit函数和_exit函数的区别
_exit :立即终止进程,不执行任何清理操作
exit : 调用清理函数、刷新缓冲区后终止进程
二、进程等待
为什么要有进程等待?
父进程在忙,子进程结束了,但无人回收,这样就造成了“死亡”的子进程一直占用资源
这个时候的子进程被称为“僵尸进程”
为了解决这个问题,最初的思路是:让父进程停下,等待子进程执行完,然后回
-
- 回收资源:子进程退出后若未回收,将残留
task_struct结构(僵尸进程)。 - 获取状态:父进程需通过等待机制获取子进程的退出码或异常信号。
- 回收资源:子进程退出后若未回收,将残留
1、wait 函数参数解析
pid_t wait(int *status);
参数说明
-
status:- 类型为
int*,是输出型参数,用于接收子进程的终止状态(如退出码或终止信号)。 - 若不关心子进程状态,可设为
NULL(如wait(NULL))
- 类型为
返回值
- 成功时返回终止的子进程 pid;
- 无子进程或调用失败时返回
2、waitpid 函数参数详解
pid_t waitpid(pid_t pid, int *status, int options);
- 参数说明
-
pid:-
> 0:等待指定 pid 的子进程; -
-1:等待任意子进程(等价于wait); -
0:等待与调用进程同进程组的所有子进程; -
< -1:等待进程组 ID 为|pid|的任意子进程。
-
-
status:- 同
wait的status参数,存储子进程终止状态。
- 同
-
options:-
0:默认阻塞模式; -
WNOHANG:非阻塞模式,若指定子进程未结束则立即返回0; -
WUNTRACED:支持作业控制,返回已暂停的子进程状态。
-
-
- 返回值
- 成功时返回子进程 pid;
- 若使用
WNOHANG且无子进程终止,返回0; - 错误时返回
-1。
waitpid 函数第二个参数详解
waitpid 函数的第二个参数 int *status 是用于接收子进程终止状态的关键参数,需配合特定宏解析具体信息。以下是详细说明:
tatus不能简单的当作整型来看,要从二进制的角度来看,32位下,整型转化为二进制有32个bit位,但是我们仅关注低16位
正常退出(子进程调用 exit 或 _exit):
if (WIFEXITED(status)) { int exit_code = WEXITSTATUS(status); // 提取低8位退出码(取值范围0~255):ml-citation{ref="2,4" data="citationList"}
}
信号终止(子进程被信号杀死):
if (WIFSIGNALED(status)) { int signal_num = WTERMSIG(status); // 提取终止信号编号(如 SIGKILL=9):ml-citation{ref="4,7" data="citationList"} printf("Terminated by signal: %d\n", signal_num);
}
暂停状态(需配合 WUNTRACED 选项):
if (WIFSTOPPED(status)) { int stop_signal = WSTOPSIG(status); // 提取暂停信号编号(如 SIGSTOP=19):ml-citation{ref="4,7" data="citationList"}
}
status 的二进制位分布:

WIFEXITED(status):判断子进程是否正常退出(返回非零值时表示正常退出)。WEXITSTATUS(status):若子进程正常退出,通过此宏获取子进程的退出码(如exit(5)中的5)。WIFSIGNALED(status):判断子进程是否因信号终止(返回非零值时表示被信号终止)。WTERMSIG(status):若子进程因信号终止,通过此宏获取信号代码(如SIGKILL对应9)
可忽略性
若父进程不关心子进程状态,可将参数设为 NULL,此时仅等待子进程结束而不获取状态信息
关键细节
- 指针的必要性:必须传递地址(如
&status),操作系统需要写入状态值到该地址。 - 状态位结构:
status的整数值包含多个信息位,需通过宏函数按需提取。 - 与
wait的关系:wait(&status)等价于waitpid(-1, &status, 0),二者的status解析方式一致