文章目录
- 进程等待
- 进程等待的必要性
- 进程等待的方法
- status参数
- option参数
进程等待
进程等待的过程其实是父进程等待子进程死亡的过程
进程等待的必要性
如果子进程退出,父进程不进行处理,子进程会变成僵尸进程,有内存泄漏的风险
僵尸进程只有父进程有权处理,其他指令对其都没有效果了
父进程创建子进程是为了完成某项任务,当子进程结束后,父进程有必要了解任务完成的如何
父进程需要对子进程进行回收
进程等待的方法
waitpid系统调用的返回值是pid_t
,如果等待成功则返回进程pid,失败则返回-1
这个函数有三个参数,第一个参数是pid_t pid
,表示需要等待的进程id,输入-1表示等待任一子进程结束
第二个参数是int* stat_loc
,这是一个输出型参数,采用指针的方法获取子进程退出状态,如果我们不关心这个状态直接传入NULL即可
第三个参数是int options
,默认为0,代表阻塞等待,也有非阻塞等待的情况
还有一个wait的系统调用,只有第二个参数,就相当于waitpid的默认使用情况
#include<sys/wait.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{
pid_t id = fork();
if(id==0)
{
int count = 5;
while(count)
{
printf("%d: 这是一个子进程,pid为:%d\n", count, getpid());
count--;
sleep(1);
}
exit(0);
}
waitpid(id,NULL,0);
printf("等待子进程\n");
return 0;
}
我们知道的是,当子进程创建出来之后,父进程是不会进入到判断语句中的,而且也没有打印等待子进程,而是一直在执行waitpid这一行,是一直等到子进程执行完毕之后才继续执行的
status参数
父进程想要了解子进程的退出码和推出信号就需要用到这个输出型参数status
而退出码和退出信号是两个数据,怎么只用一个参数来表示,这其实就用到了位图的思想,用低八位表示异常终止的信号,剩下八位表示退出的状态
画出来就是这样的
终止信号的最高位是一个core dump标志,我们暂时先不研究
因此我们就可以通过位运算来获取退出码和终止信号
退出码是(status >> 8) & 0xFF
终止信号是status & 0x7F
我们可以手动设置一下退出码来进行验证
#include<sys/wait.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{
pid_t id = fork();
int status = 0;
if(id==0)
{
int count = 5;
while(count)
{
printf("%d: 这是一个子进程,pid为:%d\n", count, getpid());
count--;
sleep(1);
}
exit(21);
}
waitpid(id,&status,0);
printf("等待子进程\n");
printf("退出码:%d; 终止信号:%d\n",(status>>8)&0xFF),status&0x7F;
return 0;
}
option参数
option参数的默认值为0,表示阻塞等待,就是说父进程啥也不干,就等着子进程结束,那如果想让父进程可以在等待的时候做自己的事情,就需要用一个宏定义WNOHANG
意思是 waiting no hang 父进程会继续运行下面的代码,因为waitpid的返回值是进程退出的pid,我们也就可以用这个来判断,子进程是否结束
然后写一个循环访问即可
例如
#include<sys/wait.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{
pid_t id = fork();
if(id==0)
{
int count = 5;
while(count)
{
printf("%d: 这是一个子进程,pid为:%d\n", count, getpid());
count--;
sleep(1);
}
exit(21);
}
while(1)
{
int wait = waitpid(id,NULL,WNOHANG);
if(wait==id)
{
printf("子进程退出,id为%d\n",wait);
break;
}
else if(wait==0)
{
printf("子进程未退出\n");
}
else
{
perror("waitpid");
exit(1);
}
sleep(1);
}
return 0;
}