wait和waitpid

wait和waitpid

当用fork启动一个子进程时,子进程就有了它自己的生命周期并将独立运行。有时,我们希望知道一个子进程何时结束。对于许多需要创建子进程的应用来说,父进程能够监测子进程的终止时间和过程是很有必要的。wait()以 及若干相关的系统调用提供了这一功能。

1.wait

系统调用wait()等待调用进程的任一子进程终止,同时在参数status所指向的缓冲区中返回该子进程的终止状态。

1 #include<sys/types.h>  
2 #include<sys/wait.h>  
3 pid_t wait(int *status);  
4 //返回:若成功则为进程ID,若出错则为-1  

系统调用wait()执行如下动作。

1.如果调用进程之前并无未被等待的子进程终止,调用将一直阻塞, 直至某个子进程终止。如果调用时已有子进程终止,wait()则立即返回。

2.如果status非空,那么关于子进程如何终止的信息则会通过status指向的整型变量返回。

3.内核将会为父进程下所有子进程的运行总量追加进程CPU时间以及资源使用

数据。

4.将终止子进程的ID作为wait()的结果返回。出错时,wait()返回-1。 可能的错误原因之一是调用进程之前并无未被等待的子进程,此时会将errno置为ECHILD。

例1:

 1 #include<stdio.h>
 2 #include<sys/types.h>
 3 #include<sys/wait.h>
 4 #include<unistd.h>
 5 #include<stdlib.h>
 6 #include<errno.h>
 7 #include<math.h>
 8 #include<string.h>
 9 
10 int main()
11 {
12     pid_t child;
13     //创建进程
14     if((child=fork())==-1)
15     {
16         printf("Fork Error :%s\n",strerror(errno));
17         exit(EXIT_FAILURE);
18     }
19     else
20     {
21         if(child==0)
22         {
23             printf("the child process is run\n");
24             sleep(1);//子进程睡眠一秒
25             printf("I am child: %d\n",getpid());
26             exit(EXIT_SUCCESS);
27         }
28         else
29         {
30             int j=0;
31             j=wait(NULL);//等待子进程退出,父进程运行
32             printf("the father process is run\n");
33             printf("the child process ID is %d\n",j);
34             printf("I am the father :%d\n",getpid());
35             return 0;
36         }    
37     }
38 }

我们可以看见父进程是在子进程运行结束之后才运行的。

现在我们尝试等待多个子进程:

例2:

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/wait.h>
 4 #include <unistd.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 
 9 
10 int main(int argc,char * argv[])
11 {
12     pid_t childPid;
13     
14     printf("fork program starting\n");
15     
16     for(int j=1;j<5;j++){
17         switch(fork())
18         {
19             case -1:
20                 perror("fork failed");
21                 exit(EXIT_FAILURE);
22             
23             case 0:
24                 printf("I am child. My PID %d, \n",getpid());
25                 sleep(1);
26                 _exit(EXIT_SUCCESS);
27             default:
28                 break;
29         }
30     }
31     //循环等待
32     while((childPid = wait(NULL)) != -1)
33     {
34         
35         sleep(1);
36         printf("wait childPid is %d\n",childPid);
37         
38     }
39     if(errno !=ECHILD)
40             exit(EXIT_FAILURE);
41     
42 }

结果:

我们可以很清楚的看见父进程创建了多个进程,但是父进程不能通过wait指定的等待某一个子进程。只能按顺序的等待下一个子进程的终止。并且如果没有子进程的退出,wait()总是被阻塞的。

2.waitpid

系统调用wait(存在诸多限制,而设计waitpidO则意在突破这些限制。

1.如果父进程已经创建了多个子进程,使用wait()将无法等待某个特定子进程的完成,只能按顺序等待下一个子进程的终止。

2.如果没有子进程退出,wait()总是保持阻塞。有时候会希望执行非阻塞的等待:是否有子进程退出,立判可知。

3.使用wait(只能发现那些已经终止的子进程。对于子进程因某个信号(如SIGSTOP或SIGTTIN)而停止,或是已停止子进程收到SIGCONT信号后恢复执行的情况就无能为力了。

  1. #include<sys/types.h>    
  2. #include<sys/wait.h>    
  3. pid_t waitpid(pid_t pid,int *status,int options);    
  4. //返回:若成功则为进程ID,若出错则为-1    

对于waitpid的pid参数的解释与其值有关:

• pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。

• pid > 0 等待其进程ID与pid相等的子进程。

• pid == 0 等待其组ID等于调用进程的组I D的任一子进程。

• pid < -1 等待其组ID等于pid的绝对值的任一子进程。

而该子进程的终止状态则通过status 返回。

options参数使我们能进一步控制waitpid的操作。

参数options是一个位掩码(bit mask),可以包含( 按位或操作) 0个或多下标志(均在SUSv3中加以规范)。

WUNTRACED:

除了返回终止子进程的信息外,还返回因信号而停止的子进程信息。

WCONTINUED: (自Linux2.6.10以来)

返回那些因收到SIGCONT信号而恢复执行的已停止子进程的状态信息。

WNOHANG:

如果参数pid所指定的子进程并未发生状态改变,则立即返回,而不会阻塞,亦即poll (轮询)。在这种情况下,waitpid()返回0。如果调用进程并无与pid匹配的子进程,则waitpid()报错,

将错误号置为ECHILD。

参考资料

Linux/Unix系统编程手册

Unix环境高级编程

Linux程序设计

posted @ 2020-05-17 01:34  图南本南  阅读(244)  评论(0编辑  收藏  举报