在2号手册里查wait()。wait()等待任意一个子进程的状态。
wait()等待成功会返回该子进程的id,返回失败会返回-1:
小实验 子进程的退出码
子进程执行work(),父进程wait子进程。
子进程跑完5秒之后就exit(0)退出。
子进程跑的时候是run状态
当子进程跑完,父进程接收到子进程的状态,即僵尸状态,然后父进程会跑10秒,10秒过后父进程也结束进程。
代码如下:
cpp
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
void work()
{
int cnt=5;
while(cnt--)
{
printf("子进程开始启动:pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);
sleep(1);
}
}
int main()
{
sleep(10);
pid_t id=fork();
if(id==0) //子进程
{
work();
exit(0);
}
else //父进程
{
pid_t ret=wait(NULL);
if(ret==id)
{
printf("wait success,pid:%d\n",getpid());
}
}
sleep(10);
return 0;
}
~
结论:子进程在跑,父进程就要进行阻塞等待。等子进程跑完,父进程才wait sucess,总结如下:
waitpid()
用法:
三个参数,重点讲一下 stauts
status是输出型参数,所谓输出型参数需要用户自己定义变量,然后传参,操作系统接收这个参数经过操作之后再返回给用户级变量
如下,定义一个int型变量,变量名为status,取地址传参,然后等如果父进程等待子进程之后就把status的值打印出来看看:
结果如下:
status是一个整形,有32位,分为高八位和低八位:
如果进程正常退出,就返回低八位的0,高八位的退出状态。
如果异常退出,就返回低七位的终止信号,为什么不是低八位呢? 低八位的第一位是core dump标志,所以只返回低七位。
如下,我们把子进程的退出码改为exit(10),再让父进程去等待:
运行结果:status为2560。
因为退出码10的二进制为1010,又因为异常所以在高八位,如下:
转化为十进制就是2560;
exit sign为stautus的信号退出码,exit code为status的进程退出码:
cpp
printf("wait success,pid:%d,status返回码:%d,
exit sign:%d ,exit code:%d\n",getpid(),ret,
status&0x7F,(status>>8)&0xFF);
为什么exit sign是 status&0x7F?
因为信号退出码在低七位 7是3个1,F是4个1,合起来就是7个1,&7个1就把低七位保留,其他位全变0
同理,exit code为高八位
运行结果:
退出信号为0,退出码为10、
如果我们把子进程的退出码改为正常退出码,即0,再跑,就会退出信号为0,退出码为0:
我们给子进程写一个除0错误:
退出信号会显示8:
我们让子进程出现空指针错误:
退出信号为11:11就是段错误:
第二个实验 手动退出
我们让子进程不要退出了,一直运行:
此时运行之后子进程就会一直跑,然后我们输入kill -9 pid终止进程,进程退出信号会显示9:
小结
父进程得到子进程的退出结果实际上是调用stautus这个整型变量,可以用一个指针解引用即可得到status。
WIFEXITED WEXITSTAUS
用这两个宏就我们就可以不用关注返回值,宏会自己获取子进程的返回值。
调用WIFEXITED获取是否正常退出,如果为假,直接输出else里面的异常。
如果为真,就调用WEXITSTAUS获取子进程的退出码并打印出来。
我们可以先搞一个异常出来,把子进程死循环:
运行:
我们再把子进程改为正常的再运行:
非阻塞轮巡/非阻塞等待
与阻塞式等待相对。
阻塞式等待父进程什么事情也不干,就在那等着子进程返回值。
阻塞式等待可以干自己的事情,等子进程返回的时候接收一下就可以了。