进程控制(四)
wait和waitpid函数
-
wait函数是waitpid函数的简单版本
-
在多进程处理时,用户可能需要用到有关进程等待的操作,这种等待可以是进程组成员间的等待,也可以是父进程对子进程的等待
-
在一个进程调用了exit之后,该进程并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构。这时的处理方法之一就是使用进程等待的系统调用wait和waitpid
wait和waitpid的函数原型是:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid,int *status,int options);
- 进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止
- 在调用了exit函数之后,一个正常的进程变成了僵尸进程,进程处于僵尸状态,但它并没有释放它的内存资源和一些重要信息(进程是否正常退出等),可以用wait和waitpid来抓住这些信息(收尸员)
- 参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果程序员对这个子进程是如何死掉的毫不在意,而只是想把这个僵尸进程消灭掉,(事实上绝大多数情况下,程序员们都会这样想),这时就可以设定这个参数为NULL,就像下面这样:
pid = wait(NULL);
- 返回值:如果成功,wait会返回被收集的子进程的ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD
下面例子体验一下wait函数的调用,wait_example.c:
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
pid_t pc,pr;
if((pc = fork())<0)
{
printf("error in fork!");
exit(1);
}
else if(pc == 0)
{
printf("this is child process with pid of %d\n",getpid());
sleep(10);
}
else
{
pr = wait(NULL);
printf("I catched a child process with pid of %d\n",pr);
}
exit(0);
}
运行结果:
hyx@hyx-virtual-machine:~/test$ ./wait_example
this is child process with pid of 13047
(等待10秒)
I catched a child process with pid of 13047
-
本质上讲,waitpid和wait作用完全相同,但waitpid多出了两个可由用户控制的参数——>pid和options,从而为用户编程提供了一种更为灵活的方式。waitpid可以用来等待指定的进程,可以使进程不挂起而立刻返回,参数pid用于指定所等待的进程,其取值及相应的含义如下表:
参数pid取值及其含义 pid取值 含义 pid > 0 只等待进程ID为pid的子进程,不管其他已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就一直等待下去 pid=-1 等待任何一个子进程退出,没有任何限制,此时waitpid等价于wait pid=0 等待同一个进程组中的任何子进程,如果某一子进程已经加入了别的进程组,waitpid则不会对它做任何理睬 pid<-1 等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值
-
参数options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED
两个选项,这是两个常数,如果使用了WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等待下去。而WUNTRACED参数,由于涉及到一些跟踪调试方面的知识,加之极少用到,先不做了解。可以用"|"运算符把它们连接起来使用,比如:ret = waitpid(-1,NULL,WNOHANG|WUNTRACED);
-
如果不想使用它们,也可以把options设为0,如:
ret = waitpid(-1,NULL,0);
一个关于waitpid的例子,waitpid_example.c:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
pid_t pc,pr;
if((pc = fork()) == 1)
{
printf("failed to create a new process\n");
exit(0);
}
else if(pc == 0)/*如果是子进程*/
{
sleep(10);/*睡眠10秒*/
exit(0);
}
do{/*如果是父进程*/
pr = waitpid(pc,NULL,WNOHANG);/*使用了WNOHANG参数,waitpid不会在这里等待*/
if(pr = 0)
{/*如果没有收集到子进程*/
printf("No child exited\n");
sleep(1);
}while(pr == 0);/*没有收集到子进程,就继续尝试*/
if(pr == pc)
{
printf("successfully get child %d\n",pr);
}
else
{
printf("some error occured\n");
}
return 0;
}
}
运行结果:
hyx@hyx-virtual-machine:~/test$ ./wait_example
this is child process with pid of 5879
(等待10秒)
I catched a child process with pid of 5879