wait系列

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

1.wait函数和waitpid函数

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。因为子进程终止是个异步事件,所以这种信号也是内核向父进程发的异步通知。父进程可以选择忽略信号,或者提供一个该信号的处理函数,对于这种信号默认动作是忽略它。调用wait或waitpid的进程可能会发生什么情况:

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

 

#include <sys/wait.h>  
pid_t wait(int *statloc); //如果成功返回进程ID,0,如果出错返回-1.  
pid_t waitpid(pid_t pid, int *statloc, int options); //如果成功返回进程ID,0(使用WNOHANG选项),如果出错返回-1.  

 

这两个函数的区别是:
  • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
  • waitpid并不等待在其调用之后的第一个终止子程序,它有若干个选项,可以控制它所等待的进程。
statloc是一个整型指针,如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内,如果不关心终止状态,则可将该参数指定为空指针。可以使用一下四个宏来查看进程的终止状态。
 
实践:
#include <stdio.h>  
#include <sys/wait.h>  
#include <stdlib.h>  
  
void pr_exit(int status){  
        printf("status = %d\n", status);  
        if(WIFEXITED(status)){  
                printf("normal terminaton, exit status = %d\n", WEXITSTATUS(status));  
        }else if(WIFSIGNALED(status)){  
                printf("abnormal termination, signal number = %d%s\n",WTERMSIG(status),  
#ifdef WCOREDUMP  
                WCOREDUMP(status)?"(core file generated)" : "");  
#else  
                "");  
#endif  
        }else if(WIFSTOPPED(status)){  
                printf("child stopped, signal number = %d\n", WSTOPSIG(status));  
        }  
}  
  
int main(void){  
        pid_t pid;  
        int status;  
  
        if((pid = fork()) < 0){  
                perror("fork");  
                return -1;  
        }else if(pid == 0){  
                exit(7);  
        }  
        if(wait(&status) != pid){  
                perror("wait");  
                return -1;  
        }  
        pr_exit(status);  
  
        if((pid = fork()) < 0){  
                perror("fork");  
                return -1;  
        }else if(pid == 0){  
                abort();  
        }  
        if(wait(&status) != pid){  
                perror("wait");  
                return -1;  
        }  
        pr_exit(status);  
  
        if((pid = fork()) < 0){  
                perror("fork");  
                return -1;  
        }else if(pid == 0){  
                status /= 0;  
        }  
        if(wait(&status) != pid){  
                perror("wait");  
                return -1;  
        }  
        pr_exit(status);  
  
        return 0;  
}  
运行结果:
[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),或是下表常量或运算的结果:
实践:
#include <stdio.h>  
#include <sys/wait.h>  
#include <unistd.h>  
  
int main(void){  
        pid_t pid;  
        int status;  
  
        if((pid = fork()) < 0){  
                perror("fork");  
                return -1;  
        }else if(pid == 0){  
                sleep(5);  
                _exit(0);  
        }  
  
        while(waitpid(pid,&status,WNOHANG) == 0){  
                printf("no terminated process.\n");  
                sleep(1);  
        }  
        printf("child terminated.\n");  
        return 0;  
}   
运行结果:
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,但提供了更多的灵活性。
#include <sys/wait.h>  
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);  
//若成功则返回0,出错则返回-1.  
id参数的作用与idtype的值相关,详细如下表:
options参数是下表各标志的按位或:
infop参数指向siginfo结构的指针,该结构包含了有关引起进程状态改变的生成信号的详细信息。
实践:
#include <stdio.h>  
#include <sys/wait.h>  
#include <unistd.h>  
  
int main(void){  
        pid_t pid, pid2;  
        siginfo_t info;  
  
        if((pid = fork()) < 0){  
                perror("fork");  
                return -1;  
        }else if(pid == 0){  
                sleep(4);  
                _exit(0);  
        }  
        while((pid2 = waitid(P_PID,pid,&info,WNOHANG)) == -1){  
                printf("no terminated process %d.\n",pid2);  
                sleep(1);  
        }  
  
        return 0;  
}  
运行结果:
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有关,该参数要求内核返回由终止进程及其所有子进程使用的资源汇总。
#include <sys/types.h>  
#include <sys/wait.h>  
#include <sys/time.h>  
#include <sys/resource.h>  
pid_t wait3(int *statloc, int options, struct rusage *rusage);  
pid_t wait4(pid_t pid, int *statloc, int option, struct rusage *rusage);  
//两个函数返回值,若成功,则返回进程ID,若出错,则返回-1.  
资源统计信息包括用户CPU时间总量,系统CPU时间总量,页面出错次数,接受到信号次数等,下表列出了各个wait函数所支持的参数。
 
4.一种避免僵死进程的方法
使用2次fork,即使不对子进程进行回收也不会出现僵死进程。
#include <stdio.h>  
#include <sys/wait.h>  
#include <stdlib.h>  
  
int main(void){  
        pid_t pid;  
        if((pid = fork()) < 0){  
                perror("fork");  
                return -1;  
        }else if(pid == 0){  
                if((pid = fork()) < 0){  
                        perror("fork");  
                        return -1;  
                }else if(pid > 0){  
                        exit(0);  
                }else{  
                        sleep(2);  
                        printf("second child,parent pid = %d\n",getppid());  
                        exit(0);  
                }  
        }  
  
        if(waitpid(pid,NULL,0) != pid){ //回收第一次fork的子进程
                perror("waitpid");  
                return -1;  
        }  
        return 0;  
}  
运行结果:
yan@yan-vm:~/apue$ ./a.out
yan@yan-vm:~/apue$ second child,parent pid = 1
parent id为1,即被init收养了。 
posted @ 2015-06-25 09:17  neteasefans  阅读(283)  评论(0编辑  收藏  举报