《UNIX环境高级编程》笔记--wait系列函数

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收养了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值