孤儿进程、僵尸进程与进程回收

孤儿进程与僵尸进程

孤儿进程:父亲死了,子进程被init进程领养
僵尸进程:子进程死了,父进程没有回收子进程的资源( PCB),父进程要知道自己儿子是怎么死的
如何回收僵尸进程:杀死父亲, init领养,负责回收
僵尸进程对系统是有危害的,他会一直占用资源

孤儿进程代码

#include <stdio.h>
#include <unistd.h>

int main()
{
    pid_t pid = fork();
    if(pid == 0 ){
        while(1){
            printf("I am child,pid=%d,ppid=%d\n",getpid(),getppid());
            sleep(1);
        }
    }else if(pid > 0){
        printf("I am parent,pid=%d,ppid=%d\n",getpid(),getppid());
        sleep(5); //父进程先结束,但是子进程没有结束, 此时父进程id会变成1
        printf("I am parent,I will die!\n");
    }
    return 0;
}

僵尸进程代码

#include <stdio.h>
#include <unistd.h>

int main()
{
    pid_t pid = fork();
    if(pid == 0){
        printf("I am child,pid =%d,ppid=%d\n",getpid(),getppid());
        sleep(4);
        printf("I am child,I will die!\n");
    }
    else if(pid > 0){
        while(1){
            printf("I am father,very happy,pid=%d\n",getpid());
            sleep(1);
        }
    }
    return 0;
}

终端查看进程信息 ps -ef

root 30214 0.0 0.0 4156 340 pts/2 S+ 14:16 0:00 ./a.out
root 30215 0.0 0.0 0 0 pts/2 Z+ 14:16 0:00 [a.out] <defunct>
root 30235 0.0 0.1 139496 1648 pts/3 R+ 14:16 0:00 ps aux
有deaunct标记的进程为将死进程

子进程回收

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果时正常终止则保存退出状态,如果时异常终止则保留着导致进程终止的信号。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除这些进程。

回收子进程,用于知晓子进程死亡的原因
作用:

阻塞等待
回收子进程资源
查看死亡原因

1. wait(int *status)

函数原型:
    pid_t wait(int *status)
 参数:
    status 传出参数,死亡原因
 返回值:
    成功返回正确的子进程ID
    失败返回 -1

子进程死亡的原因:

1.正常死亡 WIFEXITED
如果WIFEXITED为真,使用WEXITSTATUS 得到退出的状态

  1. 非正常死亡WIFSIGNALED
    如果WIFSIGNALED为真,使用WTERMSIG得到信号

2. waitpid

函数原型
    pid_t waitpid(pid_t pid, int *status, int options);
参数:
    pid  :<-1  -组id , -1 回收任意子进程, 0 回收和调用进程组内的子进程,  >0 会后指定的子进程pid
    optons: 0 与 wait 相同,也会阻塞。 WNOHANG如果当前没有子进程退出会立即返回
    status: 同上
 返回值:
    如果设置了WNOHANG,那么如果没有子进程退出,返回0.  如果有子进程退出,返回退出的pid
     失败返回-1(没有子进程)

进程组可以通过 px -ef 来查看, 找到PGID那一列

[root@VM_0_11_centos ~]# ps ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 3:53 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 3 0 0 ? -1 S 0 1:01 [ksoftirqd/0]
2 5 0 0 ? -1 S< 0 0:00 [kworker/0:0H]
一般父进程id就是组进程id

wait 函数示例代码:

#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);
        while(1){
            printf("I am child,guo lai da wo!\n");
            sleep(1);   //这里通过 kill 来杀掉这个进程,会走 WIFSIGNALED 里面的代码 status 为 9 即 signkill信号
        }
        //return 101; //return 退出认为是正常退出 会走 WIFEXITED status 为 101
        exit(102); //如果走到这里,会走 WIFSIGNALED 里面的代码 status 为 101 即我们自己的异常退出码
    }
    else if(pid > 0){
        printf("I am parent,wait for child die!\n");
        int status;

        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;
}

waitpid 示例代码

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


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

    if(pid == 0){
        printf("I am child,pid=%d\n",getpid());
        sleep(2);
    }
    else if(pid > 0){
        printf("I am parent,pid=%d\n",getpid());

        int ret ;
        while((ret= waitpid(-1,NULL,WNOHANG) ) == 0 ){
            // 没有子进程退出 返回0
            sleep(1);
        }
        //子进程退出之后再waitpid 一次,就会返回错误 -1
        printf("ret = %d\n",ret);
        ret = waitpid(-1,NULL,WNOHANG);
        if(ret < 0){
            perror("wait err");
        }
        while(1){
            sleep(1);
        }
    }
    return 0;
}

wait回收n个子进程代码示例

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

int main()
{
    int n = 5;
    int i =0;
    pid_t pid;
    for(i = 0 ;i < 5 ; i ++){
        pid = fork();
        if(pid == 0){
            printf("I am child,pid=%d\n",getpid());
            break;
        }
    }
    sleep(i);
    if(i == 5 ){
        for(i = 0; i < 5; i ++){
            pid_t wpid = wait(NULL);
            printf("wpid = %d\n",wpid);
        }
        while(1){
            sleep(1);
        }
    }
    return 0;
}

waitpid 回收n个子进程

#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 < 5 ; i ++){
        pid = fork();
        if(pid == 0){
            break;
        }
    }
    if(i == 5){
        //parent 
        printf("I am parent!");
        //如何使用waitpid回收?  -1 代表子进程都死了,都收了
        while(1){
            pid_t wpid = waitpid(-1,NULL,WNOHANG);
            if(wpid == -1){
                break;
            }
            else if(wpid > 0){
                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;
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 我们知道在unix/linux中,子进程的结束和父进程的运行是一个异步过程, 当一个进程完成它的工作终止之后,它的...
    丶Em1tu0F阅读 902评论 0 3
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,165评论 0 23
  • Linux 进程管理与程序开发 进程是Linux事务管理的基本单元,所有的进程均拥有自己独立的处理环境和系统资源,...
    JamesPeng阅读 2,509评论 1 14
  • 文/tangsl(简书作者) 原文链接:http://www.jianshu.com/p/2b993a4b913e...
    西葫芦炒胖子阅读 3,819评论 0 5
  • 影院的灯亮了,影片也在现字幕了,观影的人些却迟迟不动,也许影片像无意中伸入心里的一簇草,摇曳着敏感的枝。 明天我们...
    顽石不画阅读 295评论 0 2