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 ",strerror(errno)); 17 exit(EXIT_FAILURE); 18 } 19 else 20 { 21 if(child==0) 22 { 23 printf("the child process is run "); 24 sleep(1);//子进程睡眠一秒 25 printf("I am child: %d ",getpid()); 26 exit(EXIT_SUCCESS); 27 } 28 else 29 { 30 int j=0; 31 j=wait(NULL);//等待子进程退出,父进程运行 32 printf("the father process is run "); 33 printf("the child process ID is %d ",j); 34 printf("I am the father :%d ",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 "); 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, ",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 ",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信号后恢复执行的情况就无能为力了。
- #include<sys/types.h>
- #include<sys/wait.h>
- pid_t waitpid(pid_t pid,int *status,int options);
- //返回:若成功则为进程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程序设计