Linux进程之-孤儿进程、僵尸进程、进程回收wait与waitpid

目录:
1.了解进程的相关概念
2.掌握fork/getpid/getppid函数使用
3.掌握ps/kill命令使用
4.掌握execl/execlp函数的使用
5.什么是孤儿进程、僵尸进程
6.掌握wait函数使用
7.掌握waitpid函数的使用

概念

孤儿进程:父进程死了,子进程被init进程领养

僵尸进程:子进程死了,父进程没有回收子进程的资源(PCB)存放于内核中,变成僵尸进程。

注意:僵尸进程是不能使用kill命令清除掉的,因为kill命令只是用来终止进程的,而僵尸进程已经终止。如何回收僵尸进程?杀死父进程、init领养并负责回收。

wait函数

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

如果是异常终止,则保存着导致该进程终止的那个信号是哪个,这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。

      已知一个进程的退出状态可以在shell中用特殊变量$?查看,因为shell是它的父进程,当它终止时shell调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。

      父进程调用wait函数可以回收子进程终止信息,该函数有三个功能:

  1. 阻塞等待子进程退出
  2. 回收子进程残留资源
  3. 获取子进程结束状态(退出原因)

函数原型:pid_t wait(int *status);

  • status 传出参数
  • 返回值 成功返回终止的子进程ID, 失败返回-1.

子进程死亡原因:

  • 正常死亡:WIFEXITED,如果 WIFEXITED 为真,使用 WEXITSTATUS 得到退出状态
  • 非正常死亡:WIFSIGNALED,如果 WIFSIGNALED 为真,使用 WTERMSIG 得到信号

例子:

#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)
    {
        printf("I am child, will die!\n");
        sleep(2);
        //return 101;  //正常return退出
        exit(102);     //正常exit退出
    }
    else if(pid > 0)
    {
        printf("I am parent,wait for child die!\n");

        int status;
        //pid_t wpid = wait(NULL);
        pid_t wpid = wait(&status);
        printf("wait ok, wpid=%d,pid=%d\n",wpid,pid);

        if(WIFEXITED(status))
        {
            printf("child exit with %d\n",WEXITSTATUS(status));
        }
        if(WIFSIGNALED(status))
        {
            printf("child killed by %d\n",WTERMSIG(status));
        }
        while(1)
        {
            sleep(1);
        }
    }
    return 0;
}

输出:

~$ gcc wait_.c
~$ ./a.out
I am parent,wait for child die!
I am child, will die!
wait ok, wpid=24871,pid=24871
child exit with 102

waitpid函数

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

参数:

  • pid ,(若<-1,为组id;-1,为回收任意;0,回收和调用进程组id相同组内的子进程;>0,回收指定的pid)
  • options,(0与wait相同,也会阻塞;WNOHANG 如果当前没有子进程退出的,会立即返回)

返回值:

  • 如果设置了WNOHANG,那么如果没有子进程退出,返回0;如果有子进程退出,返回退出的pid。
  • 失败返回-1。

例子:

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

int main()
{
    int n = 5;
    int i;
    pid_t pid;
    for(i=0;i<n;i++)
    {
        pid = fork();
        if(pid == 0)
        {
            //每创建完一个子进程后退出,避免子进程又再创建子子进程
            break;
        }
    }

    if(i == 5)
    {
        //parent,如果i=5,说明子进程创建完毕,程序运行回到父进程
        printf("I am parent!\n");
        //如何使用waitpid回收? -1 代表子进程死了,都回收
        while (1)
        {
            pid_t wpid=waitpid(-1,NULL,WNOHANG);  //参数:-1,回收任意pid; 设置WNOHANG可返回回收的pid
            if(wpid == -1)
            {
                //waitpid返回值,如果没有子进程退出返回-1。
                break;
            }
            else if(wpid > 0)
            {
                //waitpid返回值,设置了WNOHANG,如果有子进程退出返回退出子进程的pid。
                printf("waitpid wpid=%d\n",wpid);
            }
        }
        while (1)
        {
            sleep(1);
        } 
    }

    if(i < 5)
    {
        sleep(i);
        printf("I am child, i=%d, pid=%d\n",i,getpid());
    }

    return 0;
}

输出:

~$ gcc nfork_waitpid.c
~$ ./a.out
I am child, i=0, pid=11033
I am parent!
waitpid wpid=11033
I am child, i=1, pid=11034
waitpid wpid=11034
I am child, i=2, pid=11035
waitpid wpid=11035
I am child, i=3, pid=11036
waitpid wpid=11036
I am child, i=4, pid=11037
waitpid wpid=11037

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值