1.为什么要等待子进程?
子进程有两种退出模式,一种是正常退出,另一种是异常退出。
正常退出是被调用了exit()函数,异常退出可能是因为调用abort函数或者被杀死(ctrl+c)。
我们关心的是子进程是不是执行完代码,是不是干完了活,干完活再去让父进程干。
父进程收集子进程的状态就能够知道子进程是否执行了代码,干完活了。
例子1:
int main()
{
pid_t pid;
int cnt=0;
int staus=10;
pid=fork();
if(pid>0){
wait(&staus);
printf("son quit static=%d\n",WEXITSTATUS(staus));
while(1){
printf("this is fathar id: %d\n",getpid());
sleep(1);
printf("cnt=%d\n",cnt);
}
}
else if(pid==0)
{
while(1){
printf("this is son id :%d\n",getpid());
sleep(1);
cnt++;
if(cnt==3){
exit(3);
}
}
}
return 0;
}
子进程执行3次后退出,wait函数等待子进程结束才往后执行代码。查询下表知想要知道wait返回的的终止状态的宏需要用WEXITSTATUS()来获取数值。
结果知父进程收集到子进程的状态,即子进程已经执行完代码了。
2.wait函数详细介绍
status参数:是一个整型数指针
非空:子进程退出状态放在它所指向的地址中。
空:不关心退出状态
使用wait函数就不会让子进程进入僵尸状态。
补充:子进程退出状态不被收集,变成僵死进程(僵尸进程)
僵尸进程的状态为Z+,可以使用ps -aux|grep (进程) 指令查询。
waitpid有一个选项可以使调用者不阻塞。
例子2:
int main()
{
pid_t pid;
int cnt=0;
int staus=10;
pid=fork();
if(pid>0){
waitpid(pid,&staus,WNOHANG);
printf("son quit static=%d\n",WEXITSTATUS(staus));
while(1){
printf("this is fathar id: %d\n",getpid());
sleep(1);
printf("cnt=%d\n",cnt);
}
}
else if(pid==0)
{
while(1){
printf("this is son id :%d\n",getpid());
sleep(1);
cnt++;
if(cnt==3){
exit(3);
}
}
}
return 0;
}
由于调用waitpid里的WHOHANG,因此父进程不堵塞,也就意味着父子进程同时进行。但由于父子进程同时进行导致子进程会出现僵尸状态。
3.孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程
Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程
例子3:
int main()
{
pid_t pid;
int cnt=0;
int staus=10;
pid=fork();
if(pid>0){
printf("this is fathar id: %d\n",getpid());
}
else if(pid==0)
{
while(1){
printf("this is son id :%d,father pid is:%d\n",getpid(),getppid());
sleep(1);
cnt++;
if(cnt==3){
exit(3);
}
}
}
return 0;
}
父进程比子进程先结束,子进程变成孤儿进程,但系统不允许,会被系统的Init进程收留,init进程为1。