一、前言
其实僵尸进程产生的主要原因就是操作系统要保留结束的子进程的状态,尤其是其返回值,以供主进程使用。要销毁僵尸进程,释放僵尸进程的资源。,我们需要父进程利用函数向操作系统索要该子进程的返回值,当我们难道子进程的返回值后,操作系统就会回收该进程的资源。当子进程结束时,它会把返回值交给操作系统,而操作系统会把该值放到系统的一片内存中,我们要获取该值,要做的就是利用函数读取该内存块中值。
二、wait函数
利用wait函数我们可以获取上述子进程的返回值。wait函数是阻塞函数,其原型如下: #include <sys/wait.h>
pid_t wait(int *status);
wait函数可以等待任意子进程结束,其返回值是该子进程的进程ID。其参数是读取的上述子进程返回值的地址。因为该地址保存的数据不仅仅包含子进程的返回值,还包含子进程是否是正常结束的布尔量,我们可以利用下面的宏获取需要的信息:
WIFEXITED(status),表示子进程是否正常结束。
WEXITSTATUS(status),表示子进程的返回值。
示例代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
int status;
pid_t pid=fork();
if(pid==0)
{
sleep(20);
return 3;
}
else
{
printf("当前子进程ID:%d\n",pid);
wait(&status);
if(WIFEXITED(status))
printf("子进程返回值:%d\n",WEXITSTATUS(status));
}
return 0;
}
由于wait是阻塞函数,当执行到wait时,子进程正在sleep,而父进程会进行阻塞,直到子进程sleep完返回3之后才会停止阻塞。
下面是执行结果:
[Hyman@Hyman fork]$ gcc wait.c
[Hyman@Hyman fork]$ ./a.out
当前子进程ID:9799
子进程返回值:3
三、waitpid函数
waitpid函数也可以等待指定的进程返回 并回收僵尸进程资源。但它不同于Wait,它是非阻塞函数,其原型定义如下:
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
pid表示要等待的子进程ID,如果写-1表示等待任意子进程结束
status和wait的status含义一样,表示指向子进程返回值内存的指针。options是常量WNOHANG,表示即使没有结束的子进程也不会阻塞,而是返回0并退出函数。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
int main()
{
int status;
pid_t pid=fork();
if(pid==0)
{
sleep(20);
return 3;
}
else
{
printf("当前子进程ID:%d\n",pid);
while(waitpid(pid,&status,WNOHANG)==0)
{
printf("主进程sleep 4秒\n");
sleep(4);
}
if(WIFEXITED(status))
printf("子进程返回值:%d\n",WEXITSTATUS(status));
}
return 0;
}
执行结果如下:
[Hyman@Hyman fork]$ gcc wait.c
[Hyman@Hyman fork]$ ./a.out
当前子进程ID:9893
主进程sleep 4秒
主进程sleep 4秒
主进程sleep 4秒
主进程sleep 4秒
主进程sleep 4秒
子进程返回值:3
从上述结果中也可以看出可以看到waitpid并没有阻塞,而是一直在执行while中的语句,直到子进程结束。
Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
git clone git@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL12