wait系列函数

来源:互联网 发布:万能数据恢复大师官网 编辑:程序博客网 时间:2024/06/03 16:08

http://blog.csdn.net/todd911/article/details/15028511

1.wait函数和waitpid函数

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件,所以这种信号也是内核向

父进程发的异步通知。父进程可以选择忽略信号,或者提供一个该信号的处理函数,对于这种信号默认动作是忽略它。调用wait或

waitpid的进程可能会发生什么情况:

  • 如果其所有子进程都在运行,则阻塞。
  • 如果一个子进程已经终止,正等待父进程获取其终止状态,则取得该紫禁城的终止状态后返回。
  • 如果它没有任何子进程,则立即出错返回。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <sys/wait.h>  
  2. pid_t wait(int *statloc); //如果成功返回进程ID,0,如果出错返回-1.  
  3. pid_t waitpid(pid_t pid, int *statloc, int options); //如果成功返回进程ID,0(使用WNOHANG选项),如果出错返回-1.  

这两个函数的区别是:
  • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
  • waitpid并不等于在其调用之后的第一个终止子程序,它有若干个选项,可以控制它所等待的进程。
statloc是一个整型指针,如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内,如果不关心终止状态,
则可将该参数指定为空指针。可以使用一下四个宏来查看进程的终止状态。


实践:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <sys/wait.h>  
  3. #include <stdlib.h>  
  4.   
  5. void pr_exit(int status){  
  6.         printf("status = %d\n", status);  
  7.         if(WIFEXITED(status)){  
  8.                 printf("normal terminaton, exit status = %d\n", WEXITSTATUS(status));  
  9.         }else if(WIFSIGNALED(status)){  
  10.                 printf("abnormal termination, signal number = %d%s\n",  
  11.                 WTERMSIG(status),  
  12. #ifdef WCOREDUMP  
  13.                 WCOREDUMP(status)?"(core file generated)" : "");  
  14. #else  
  15.                 "");  
  16. #endif  
  17.         }else if(WIFSTOPPED(status)){  
  18.                 printf("child stopped, signal number = %d\n", WSTOPSIG(status));  
  19.         }  
  20. }  
  21.   
  22. int main(void){  
  23.         pid_t pid;  
  24.         int status;  
  25.   
  26.         if((pid = fork()) < 0){  
  27.                 perror("fork");  
  28.                 return -1;  
  29.         }else if(pid == 0){  
  30.                 exit(7);  
  31.         }  
  32.         if(wait(&status) != pid){  
  33.                 perror("wait");  
  34.                 return -1;  
  35.         }  
  36.         pr_exit(status);  
  37.   
  38.         if((pid = fork()) < 0){  
  39.                 perror("fork");  
  40.                 return -1;  
  41.         }else if(pid == 0){  
  42.                 abort();  
  43.         }  
  44.         if(wait(&status) != pid){  
  45.                 perror("wait");  
  46.                 return -1;  
  47.         }  
  48.         pr_exit(status);  
  49.   
  50.         if((pid = fork()) < 0){  
  51.                 perror("fork");  
  52.                 return -1;  
  53.         }else if(pid == 0){  
  54.                 status /= 0;  
  55.         }  
  56.         if(wait(&status) != pid){  
  57.                 perror("wait");  
  58.                 return -1;  
  59.         }  
  60.         pr_exit(status);  
  61.   
  62.         return 0;  
  63. }  
运行结果:
[yan@yanPC apue]$ ./a.out
status = 1792
normal terminaton, exit status = 7
status = 134
abnormal termination, signal number = 6(core file generated)
status = 136
abnormal termination, signal number = 8(core file generated)


waitpid可以等待一个特定的进程结束。对于waitpid函数中的pid参数的作用解释如下:
pid == -1    等待任意子进程,与wait等效。
pid > 0  等待进程ID等于pid的子进程。
pid == 0  等待其组ID等于调用进程组ID的任意子进程。
pid < -1 等待其组ID等于pid绝对值的任一子进程。
options参数使我们能进一步控制waitpid的操作。参数可以使0(不是用options),或是下表常量或运算的结果:

实践:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <sys/wait.h>  
  3. #include <unistd.h>  
  4.   
  5. int main(void){  
  6.         pid_t pid;  
  7.         int status;  
  8.   
  9.         if((pid = fork()) < 0){  
  10.                 perror("fork");  
  11.                 return -1;  
  12.         }else if(pid == 0){  
  13.                 sleep(5);  
  14.                 _exit(0);  
  15.         }  
  16.   
  17.         while(waitpid(pid,&status,WNOHANG) == 0){  
  18.                 printf("no terminated process.\n");  
  19.                 sleep(1);  
  20.         }  
  21.         printf("child terminated.\n");  
  22.         return 0;  
  23. }  
运行结果:
yan@yan-vm:~/apue$ ./a.out
no terminated process.
no terminated process.
no terminated process.
no terminated process.
no terminated process.
child terminated.
使用了WNOHANG,因为没有结束的子进程,waitpid直接返回。

2.waitid函数

Single Unix Specification的XSI扩展包括了另一个取得进程终止状态的函数--waitid,该函数类似于waitpid,但提供了更多的
灵活性。
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <sys/wait.h>  
  2. int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);  
  3. //若成功则返回0,出错则返回-1.  
id参数的作用与idtype的值相关,详细如下表:

options参数是下表各标志的按位或:

infop参数指向siginfo结构的指针,该结构包含了有关引起进程状态改变的生成信号的详细信息。
实践:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <sys/wait.h>  
  3. #include <unistd.h>  
  4.   
  5. int main(void){  
  6.         pid_t pid, pid2;  
  7.         siginfo_t info;  
  8.   
  9.         if((pid = fork()) < 0){  
  10.                 perror("fork");  
  11.                 return -1;  
  12.         }else if(pid == 0){  
  13.                 sleep(4);  
  14.                 _exit(0);  
  15.         }  
  16.         while((pid2 = waitid(P_PID,pid,&info,WNOHANG)) == -1){  
  17.                 printf("no terminated process %d.\n",pid2);  
  18.                 sleep(1);  
  19.         }  
  20.   
  21.         return 0;  
  22. }  
运行结果:
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
no terminated process -1.
.......
按照说明,waitid一直返回-1,也就是一直出错,再看下进程状态。
yan       5147  0.0  0.0   2008   280 pts/2    S    14:10   0:00 ./a.out
yan       5148  0.0  0.0      0     0 pts/2    Z    14:10   0:00 [a.out] <defunct>
子程序已经僵死了,但是父进程无法回收它,这边真的不明白是什么原因,望高人指点~~~~

3.wait3和wait4函数

大多数UNIX系统实现了另外的两个函数wait3和wait4.历史上,这2个函数是UNIX系统的BSD分支沿袭下来的。它们提供的功能比POSIX.1
函数wait,waitpid和waitid所提供的功能要多一个,这与附加参数rusage有关,该参数要求内核返回由终止进程及其所有子进程使用的资源
汇总。
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/wait.h>  
  3. #include <sys/time.h>  
  4. #include <sys/resource.h>  
  5. pid_t wait3(int *statloc, int options, struct rusage *rusage);  
  6. pid_t wait4(pid_t pid, int *statloc, int option, struct rusage *rusage);  
  7. //两个函数返回值,若成功,则返回进程ID,若出错,则返回-1.  
资源统计信息包括用户CPU时间总量,系统CPU时间总量,页面出错次数,接受到信号次数等,下表列出了各个wait函数所支持
的参数。


4.一种避免僵死进程的方法

使用2次fork,即时不对子进程进行回收也不会出现僵死进程。
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <sys/wait.h>  
  3. #include <stdlib.h>  
  4.   
  5. int main(void){  
  6.         pid_t pid;  
  7.         if((pid = fork()) < 0){  
  8.                 perror("fork");  
  9.                 return -1;  
  10.         }else if(pid == 0){  
  11.                 if((pid = fork()) < 0){  
  12.                         perror("fork");  
  13.                         return -1;  
  14.                 }else if(pid > 0){  
  15.                         exit(0);  
  16.                 }else{  
  17.                         sleep(2);  
  18.                         printf("second child,parent pid = %d\n",getppid());  
  19.                         exit(0);  
  20.                 }  
  21.         }  
  22.   
  23.         if(waitpid(pid,NULL,0) != pid){ //回收第一次fork的子进程,但是第二个没有回收  
  24.                 perror("waitpid");  
  25.                 return -1;  
  26.         }  
  27.         return 0;  
  28. }  
运行结果:
yan@yan-vm:~/apue$ ./a.out
yan@yan-vm:~/apue$ second child,parent pid = 1
parent id为1,即被init收养了。


子进程的结束状态返回后存于status,底下有几个宏可判别结束情况
WIFEXITED(status)如果子进程正常结束则为非0值。
WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。
WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真
WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。
WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。
WSTOPSIG(status)取得引发子进程暂停的信号代码。

1,WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。

(请注意,虽然名字一样,这里的参数status并不同于wait唯一的参数--指向整数的指针status,而是那个指针所指向的整数,切记不要搞混了。)

2,WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status)就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说,WIFEXITED返回0,这个值就毫无意义。



0 0
原创粉丝点击