进程终止
进程的退出场景有三个
1.代码运行完毕,结果正确
2.代码运行完毕,结果不正确
3.代码异常终止(程序崩溃)
问题:
main函数为什么要return 0?
main函数的返回值是进程的退出码,退出码传给其父进程。
echo $? // 输出最近一次进程退出时对应的进程码
退出码的意义是可以帮助我们判断程序运行完时结果是正确还是错误,一般0代表结果正确,!0代表结果错误,而程序崩溃后退出码会变得没有意义。
1.main函数return代表程序退出,非main函数叫函数返回
2.可以使用exit(int value) (头文件<stdlib.h>)来使一个正常程序停止,参数代表退出时的退出码。
printf("hello world!");
sleep(4);
exit(EXIT_SUCCESS);
return 0;
执行该代码4秒后才会刷新出字符串,原因是字符串后无‘/n’,数据会暂时保存在缓冲区。而exit和main函数的return会要求系统刷新缓冲区。
同时有_exit函数,也可以终止进程但不能刷新缓冲区(强制终止程序,但不进行包括刷新缓冲区在内的收尾工作)
系统层面:进程退出后少了一个进程:free pcb,free 页表和各种映射关系,代码和数据申请的空间也要释放。
进程等待
什么是进程等待?
fork出一个子进程往往是为了帮助父进程完成某种任务,那么父进程需要知道子进程的完成结果,所以需利用wait,waitpid等待子进程退出。
进程等待存在的原因有3个
1.通过获取子进程退出的信息,能够得知子进程的执行结果
2.保证时序问题:子进程先退出,父进程后退出
3.进程退出时会先进入僵尸状态,造成内存泄漏,需通过父进程wait释放子进程占用的资源
如何等待
#include <sys/types.h>
#include <sys/wait.h>
wait(int *status);
waitpid(pid_t pid, int *status, int option);
父进程得到的status结果与子进程如何退出相关,status要让父进程得到子进程执行的结果
status占用32个比特位,只关注低16位
我们已经知道进程退出场景中的前两个情况下我们能通过退出码来得知子进程的完成情况,那我们该怎么去了解第三种情况下子进程的完成情况呢?第三种情况的本质是因为这个进程因为异常问题,导致自己收到了某种信号,所以我们可以通过信号来了解进程出现的问题,而我们可以用status参数来得到退出码和终止信号。正如上图所表示的第八位是退出信号,当程序正常退出时,后八位都是0,次后8位代表退出码。
判断一个程序是否是正常退出只需判断是否接收到信号,status & 0x7f
标志位 = (status>>7)&0x1
退出码 = (status>>8)&0xff
另外使用位运算比较麻烦所以可以用宏来替代:
WIFEXITED(status):若正常终止子进程的返回状态则为真
WEXITSTATUS(status):若WEXITSTATUS非零返回子进程的退出码
status值是如何得到的
pcb中存储了进程的数据,其中就包括了进程的终止信号和退出码,所以只需要用我们传入的status带回即可
*status_p |= exit_code
*status_p |= signal