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

孤儿进程与僵尸进程

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

孤儿进程代码

#include 
#include 

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 
#include 

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]
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 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 


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 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 

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

你可能感兴趣的:(孤儿进程、僵尸进程与进程回收)