首先我们来看看调用wait()和waitpid()会发生什么。
- 如果其所以子进程都还在运行,则阻塞。
- 如果一个子进程已终止,正等待父进程获取其终止进程,则取得该子进程的终止状态立即返回。
- 如果它没有任何子进程,则立即出错返回。
另外,要知道当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。而如果父进程由于接受到SIGCHLD信号而调用wait,我们期望wait会立即返回。如果在随机时间点调用wait,则进程会阻塞。
函数头文件及声明:
#include<sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);
两函数如果成功,返回进程ID;若出错返回0或-1;
这两个函数的区别如下:
- 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
- waitpid并不等待在其调用之后的第一个终止进程,它有若干个选项,可以控制它所等待的进程。
如果子进程已经终止,并且是僵死进程,那么wait立即返回并取得该子进程的状态;否则wait使其调用者也就是父进程阻塞,直到一个子进程终止。如果调用者阻塞,而调用者有很多子进程,那么就在其某一子进程终止时,wait就立即返回。
现在我们来看看这两个函数的参数
它们的参数中都有一个整形指针statloc。如果statloc不是空,则终止进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可以将该参数制定为空,比如wait(NULL);
waitpid()参数中pid的作用:
pid | 解释 |
---|---|
等于-1 | 等待任一子进程。此时,waitpid和wait等效 |
大于0 | 等待进程ID与pid相等的子进程 |
等于0 | 等待组ID等于调用进程组ID的任一子进程 |
小于-1 | 等待组ID等于pid绝对值的任一子进程 |
这里,对于wait,如果父进程调用进程没有子进程,则会出错。对于waitpid,如果制定的进程不存在,或者参数pid指定的进程不是子进程,都可能会出错。
参数options,这个参数让我们可以进一步的控制waitpid的操作。
常量 | 说明 |
---|---|
0 | 同wait,阻塞父进程,等待子进程退出 |
WCONTINUED | 若实现支持作业控制,那么由pid指定的任一子进程在停止后已经继续,但其状态尚未报告,则返回其状态(不懂。。。) |
WNOHANG | 若由pid指定的子进程不是立即可用的,则waitpid不阻塞,此时返回值为0 |
WUNTRACED | 如果子进程进入暂停执行情况则马上返回,对结束状态不予理会 |
waitpid非阻塞实例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
int main(void)
{
pid_t pc,pr;
pc=fork();
if(pc<0)
{
printf("Error fork \n");
}
else if(pc==0)
{
sleep(5);
exit(0);
}
else
{
do
{
pr=waitpid(pc,NULL,WNOHANG);
if(pr==0)
{
printf("The child process has not exited \n");
sleep(1);
}
}while(pr==0);
if(pr==pc)
{
printf("Get child exit code: %d\n ",pr);
}
else
{
printf("Some error occured. \n");
}
}
return 0;
}
waitpid与wait:
1)waitpid可等待一个特定的进程,而wait则返回任一个终止子进程的状态。
2)waitpid提供一个wait的非阻塞版本。
3)waitpid通过WUNTRACED和WCNOTINUED支持作业控制。