一、进程终止
即正在执行的程序停止执行,操作系统进行系统资源释放(进程申请的相关内核数据结构和代码数据)。
进程是用来完成某个任务的,所以结束时无非三种情况:
- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码异常终止
1、退出码
我们在以前写 main 函数时,总在最后返回一个 0,这个 0 其实就是退出码。0 就表示我们的程序运行完毕,结果正确;结果不正确就可能返回其他非 0 的退出码。那怎么查看这些退出码呢?
退出码:进程终止时返回给操作系统一个整数(0~133),用来标识进程的终止状态。
我们可以借助 strerror 函数,strerror 是 C 标准库中的核心函数(定义在<string.h>头文件),核心作用是将系统的「错误码(errno)」转换为人类可读的字符串描述。
2、常见退出方法
2.1 正常终止
-
main 函数返回 我们可以通过
echo $?查看进程退出码。 -
_exit 参数:status 定义了进程的终止状态,父进程通过 wait 来获取该值。 说明:虽然 status 是 int,但是仅有低 8 位可以被父进程所用。所以 _exit(-1) 时,在终端执行 $? 发现返回值是 255。
-
exit
那么_exit 和 exit 有什么区别呢?
_exit 属于系统调用(内核态底层),而 exit 属于标准库中的函数。
exit 在底层调用了 _exit,但在此之前还进行了执行用户定义的清理函数和刷新缓冲区,关闭流等操作。
我们可以通过一个实验验证一下:在 printf 时我们先不用换行刷新缓冲区。
所以说,缓冲区一定不在系统内部,而是库缓冲区,C 语言提供。
2.2 异常退出
进程未完成预期功能,因外部信号或内部错误被迫中断,终止状态为「错误」。
- ctrl + c,信号终止
收到外部信号:
SIGINT(信号 2):用户在终端按下Ctrl+C,终止前台运行的进程SIGKILL(信号 9):强制终止进程,无法被捕获或忽略(命令:kill -9 进程 PID),用于终止无响应的进程。
程序内部运行错误:进程执行过程中出现无法恢复的逻辑错误,触发内核终止信号,例如:
- 除零错误(
int a = 1 / 0;) - 栈溢出(递归调用无终止条件,耗尽栈空间)
- 自定义类型的非法操作(如未初始化的指针调用成员函数)
注意:当进程发生异常退出,此时退出码无意义。
二、进程等待
1、进程等待的必要性
前面我们在进程状态中提到,当子进程结束,父进程不去获取子进程的退出信息,那么此时该子进程就会变成僵尸进程,操作系统依然需要维护相关的数据结构,就会造成内存泄漏。进程等待的一个重要作用就是回收子进程资源,防止内存泄漏,同时,获取子进程的退出信息。
2、进程等待的方式
2.1 wait 方法
等待任意一个退出的子进程,并返回子进程 pid。如果子进程一直不退出,父进程就会一直阻塞在 wait 处。
#include<stdlib.h>
#include
{
id = fork();
(id == )
{
cnt = ;
(cnt--)
{
(,getpid(),getppid());
sleep();
}
();
}
sleep();
rid = wait();
(rid > ) (,rid);
;
}


