wait和waitpid函数

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。

父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。

#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *status);

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

例如:一个进程的退出状态(比如:return 0;)可以在Shell中用特殊变量$?查看,因为Shell是它的父进程,当它终止时Shell调用wait或waitpid得到它的退出状态的同时彻底清除掉这个进程。

如果一个进程已经终止,但是它的父进程尚未调用wait或waitpid对它进行清理,这时的进程状态称为僵尸(Zombie)进程,可以用ps u查看进程状态。 

父进程调用wait或waitpid时可能会:

        1.阻塞(如果它的所有子进程都还在运行)。ps:Shell就是阻塞等着子进程运行完毕。

        2.带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。

        3.出错立即返回(如果它没有任何子进程)。

wait和waitpid区别:

        如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而在调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。

下面这段程序,子进程先死了,变成僵尸进程,父进程一直在睡觉:

#include "./common/head.h"

/*功能:
 *子进程先死,变成僵尸进程,父进程不给它收尸,一直在睡觉。
*/

int main()
{
    pid_t pid = fork();
    if(pid < 0){
        perror("fork");
        exit(1);
    }
    if(pid){    //父进程
        //一直睡觉,不给子进程收尸
        while(1)    sleep(1);
    }else{    //子进程
        exit(1);    //子进程先死,变成僵尸进程
    }

    return 0;
}

过程解析:

子进程先于父进程死,父进程却没给它收尸,子进程变成了僵尸进程。当我们再打开一个终端,用ps u命令查看,发现父进程状态是S(睡眠),子进程状态是Z(僵尸)。如果用Ctrl+c结束父进程,则父进程会被Shell收尸,这时,子进程变成了孤儿僵尸,会被1号进程回收。值得一提的是,用kill -9命令杀不掉僵尸进程,当kill -9杀掉僵尸的父进程后,父进程会被父进程的父进程(在这里就是Shell收尸),孤儿僵尸因为父亲死了,会被1号进程收养,此时用ps u已经查看不到父进程和子进程了。

用waitpid函数获取子进程死亡原因: 

#include "./common/head.h"

/*功能:
 *用waitpid函数获取子进程死亡原因。
*/

int main()
{
    pid_t pid = fork();
    if(pid < 0){
        perror("fork");
        exit(1);
    }

    if(pid == 0){    //子进程
        int n = 5;
        while(n--){    //子进程5秒后结束
            printf("this is child process\n");
            sleep(1);
        }
        exit(3);    //父进程中打印正常退出代码为3
    }else{    //父进程
        int stat_val;
        //等待子进程退出
        wait(pid, &stat_val, 0);    //pid为-1时代表等待所有子进程结束,子进程结束的信息存储在stat_val中,可以用以下的宏来进行判断
        if(WIFEXITED(stat_val)){    //子进程正常退出
            //打印正常退出代码,即上面返回的3
            printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
        }else if(WIFSIGNALED(stat_val)){    //子进程是被信号终止的
            //打印信号
            printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值