wait 函数
wait函数的作用是父进程调用,等待子进程退出,回收子进程的资源;
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
waitpid 函数
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
参数为0:也就是阻塞版本的等待,也就是说该waitpid在子进程没有退出情况下就不会返回,就和wait的使用一模一样,因为wait的使用就是阻塞版本的等待方式;
参数为WNOHANG: 这是一个宏,表示调用wait为非阻塞的版本,非阻塞也就以为执行带waitpid函数会立即返回;
而设置这个参数:返回情况有以下几种:
若pid指定的子进程没有结束,则waitpid()函数返回0,父进程不予以等待;
若正常结束,则返回该子进程的ID;
若等待失败,即返回小于0。
waitpid 的options参数的理解
该参数设置:一般设置为WNOHANG:表示为父进程是以非阻塞的方式等待子进程;
但是非阻塞方式等待子进程退出就有几种情况:
1. 子进程没有退出,但是父进程调用的waitpid返回了0,这也表示等待子进程成功,只不过子进程没有退出,此时表示需要继续做父进程的事情;
2. 子进程退出了,父进程调用waitpid函数返回子进程的PID, 也就是等待成功了,这时候我们在父进程可以拿到子进程的退出状态信息;
3. waitpid等待子进程退出失败,waitpid就会返回小于0的值,此时就可以做一些输出错误信息给用户;
阻塞本质就是:调用该函数的父进程由在运行队列被放入到了等待队列中等待,同时修改进程状态为S。
waitpid返回的本质也就是:将该父进程从等待队列拿到运行队列中执行;
测试options:WNODHANG
非阻塞等待子进程;
一般而言我们会使用一种叫做非阻塞轮回检测技术来检测子进程的退出状态。也就是说:我希望子进程退出能够被我父进程检测到,同时我又不希望我父进程处于阻塞等待,也就是父进程不希望自己什么事都不可以做,只等子进程退出返回;使用while循环保持检测,直到子进程退出。
//父进程调用waitpid函数完成对子进程的回收
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
//创建子进程
pid_t pid = fork();
if(pid<0) //fork失败的情况
{
perror("fork error");
return -1;
}
else if(pid>0)//父进程
{
printf("father: [%d], pid==[%d], fpid==[%d]\n", pid, getpid(),getppid());
int status;//该变量是父进程的变量,为的是在父进程获得子进程的退出状态的信息
/***************************************************
*这个循环就是继续轮回检测的非阻塞版本的设计,
*假如子进程没退出,我们一直死循环检测知道直到它退出
****************************************************/
while(1)
{
// -1表示任意子进程,WNOHANG:不阻塞
pid_t wpid = waitpid(-1, &status, WNOHANG);
printf("wpid==[%d]\n", wpid);
if(wpid > 0) //waitpid 等待成功,子进程退出,父进程就可以获取子进程的信息
{
if(WIFEXITED(status)) //正常退出
{
printf("child normal exit, status==[%d]\n", WEXITSTATUS(status));
}
else if(WIFSIGNALED(status)) //被信号杀死
{
printf("child killed by signal, signo==[%d]\n", WTERMSIG(status));
}
}
else if(wpid == 0) //子进程还活着,表示waitpid等待成功,但是子进程还没有退出,waitpid返回0回到父进程的代码执行
{
printf("Child is living, wpid == [%d]\n", wpid);
}
else if((wpid == -1) //子进程全部退出
{
printf("No child is living, wpid == [%d]\n", wpid);
break;
}
}
sleep(20);//让父进程每隔20秒去检测
}
else if(pid==0) //子进程
{
printf("child: pid==[%d], fpid==[%d]\n", getpid(), getppid());
sleep(2);
return 9;
}
return 0;
}