进程退出
正常退出
1.Main函数调用return
2.进程可以调用exit(),标准c库
3.进程可以调用_exit()或着 _Exit(),属于系统调用
补充:
1.进程最后一个线程返回
2.最后一个线程调用prhread_exit
异常退出
1.调用abort
2.当进程收到某些信号时,如ctrl+c
3.最后一个线程对取消(cancella)请求做出响应
不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。
对于上述任意一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit、_exit和_Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传递给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。
等待子进程退出
为什么要等待子进程退出?
创建子进程的目的是让子进程去干活,干活到底是干完了还是没有干完。
干完了可以根据子进程的退出码查看工作的完成情况。
没干完是发生什么情况导致进程退出。
1、子进程退出状态不被收集,变成僵死进程。
2、父进程等待子进程退出,并收集子进程的退出状态。
收集子进程的退出状态 wait函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
wait都有一个状态码
status参数是一个整型数指针
非空:子进程退出状态放在它所指向的地址中。
空:不关心退出状态
这里先运行子进程3次,然后结束子进程,回传数字5,回传的数被收集,最后通过WEXITSTATUS来解析这个数。
正常退出,调用WEXITSTATUS(status)来检测子进程回传的数5.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
int status = 10;
pid = fork();
if(pid>0)
{
wait(&status);
printf("child quit,child status = %d\n",WEXITSTATUS(status));
while(1){
printf("this is father print,pid = %d\n",getpid());
sleep(1);
printf("cnt = %d\n",cnt);
}
}
else if(pid == 0)
{
while(1){
printf("this is child print,pid = %d\n",getpid());
sleep(1);
cnt++;
if(cnt == 3){
exit(5);
}
}
}
return 0;
}
孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程
Linux避免系统存在过多的孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt = 0;
pid = fork();
if(pid>0)
{
printf("this is father print,pid = %d\n",getpid());
}
else if(pid == 0)
{
while(1){
printf("this is child print,pid = %d,father pid = %d\n",getpid(),getppid());
sleep(1);
cnt++;
if(cnt == 5){
exit(0);
}
}
}
return 0;
}
这里父进程子进程一起运行,父进程只运行一次。
第一次子进程输出父进程的pid,但父进程结束后,子进程输出的父进程的pid为1,被init进程收留。