进程等待 wait和waitpid

父进程通过 waitwaitpid 函数来获取子进程的退出状态,并且彻底杀死这个进程,清理这个进程的所有资源。如果不这么做,子进程会变成一个僵尸进程,长时间占用系统内存,造成类似内存泄漏的问题。

wait()

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);

参数:输出型参数,获取子进程的退出状态,不关心可以设置为NULL;
返回值:成功返回被等待进程的 pid, 失败返回 -1。

当一个进程终止时,内核就会向其父进程发送 SIGCHLD 异步(即在任意时刻内核都可以向父进程发送)信号。父进程既可以选择忽略该信号,也可以提供一个信号处理函数,对该信号的默认动作是忽略。

那么父进程调用 wait 之后会发生什么?

  • 如果没有运行完成的子进程,则父进程会阻塞等待,直到有一个子进程结束,则 wait 函数返回;
  • 如果有一个或多个子进程结束,则 wait 直接返回,即只要收到 SIGCHLD 信号,则wait 就会返回;
  • 如果该进程没有子进程,则 wait 就会失败,返回 -1。

如果 status 参数不为空,则它里面保存了 子进程的退出状态,我们可以通过几个来获取子进程的退出状态信息。
实际上 status 在不同情况下有不同的含义,它的内容大概如下:
这里写图片描述

看下面这份代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    pid_t pid = fork();

    if(pid < 0){
        perror("fork");
        return 1;
    }
    else if(pid > 0){//father
        printf("father start!\n");
        int status;
        int ret = wait(&status);
        if(ret > 0 && (status & 0xff) == 0){//正常退出
            printf("exit code: %d\n", (status>>8)&0xff);
        }else{//异常退出
            printf("sig code: %d\n", status&0x7f);
        }
        printf("father end\n");
    }else{//child
        printf("child start!\n");
        printf("child end\n");
        exit(99);
    }

    return 0;
}

它的运行结果如下:
这里写图片描述

可以看到子进程正常退出,而我们取得 status 的高八位正是子进程的退出码。我们在通过异常信号终止子进程,看看 status 的内容。

waitpid

pid_t waitpid(pid_t pid, int *status, int option);

返回值:

成功返回子进程 pid;
如果设置了 WNOHANG, 则当父进程没有发现已经结束的进程,则它不会阻塞等待,而是直接返回0;
调用中出错返回-1,errno 会被设置;
当 pid 所指示的进程不存在或不是该进程的子进程,则会出错返回,errno会被设置为ECHILD。

参数:

  • pid==-1,等待任意一个子进程,pid == 0 等待组 id 等于调用者组 id 的任意一个进程,pid > 0 等待进程id与参数pid相等的进程,pid<-1, 等待子进程id与 pid 绝对值相等的进程。
  • status:正常退出时,高八位表示退出码,异常退出时,低七位表示终止信号,可以用宏WIFEXITED(status) 提取退出状态,当为正常退出时,该宏为真,宏 WEXITSTATUS(status) 用来查看正常退出时的退出码,我们也可以通过位运算查看status的内容信息;
  • option:WNOHANG,当子进程没有结束时,父进程返回0,即不会阻塞式等待。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
    pid_t pid = fork();

    if(pid < 0){
        perror("fork");
        return 1;
    }
    else if(pid > 0){//father
        printf("father start!\n");
        int status;
        int ret = waitpid(-1, &status, WNOHANG);//设置WNOHANG选项
        if(ret > 0 && (status & 0xff) == 0){
            printf("ret: %d\n", ret);
            printf("exit code: %d\n", (status>>8)&0xff);
        }else if (ret == 0){
            printf("no child finish\n");
        }
        else{
            printf("ret: %d\n", ret);
            printf("sig code: %d\n", status&0x7f);
        }
        printf("father end\n");
    }else{//child
        printf("child start!\n");
        sleep(100);
        printf("child end\n");
        exit(99);
    }

    return 0;
}

运行结果:
这里写图片描述
当设置了 WNOHANG 选项后,父进程没有等待子进程而是直接返回0。

——完!


【作者:果冻:http://blog.csdn.net/jelly_9

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值