进程控制(四)

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中只支持WNOHANGWUNTRACED
    两个选项,这是两个常数,如果使用了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

你可能感兴趣的:(进程控制(四))