zoukankan      html  css  js  c++  java
  • 回收子进程

    1.孤儿进程
    父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程
    2.僵尸进程
    子进程终止,父进程尚未回收,子进程残留资源(PCB)存放在内核中,变成僵尸(zombie)进程
    特别注意:僵尸进程是不能使用kill命令清除掉的。以为kill命令只能终止活着的进程,而僵尸进程已经终止。
    3.回收僵尸进程
    模拟一个僵尸进程:zombie.c

       #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/wait.h>
        
        int main(void)
        {
                pid_t pid;
                pid = fork();
        
                if(pid == 0) {
                        printf("----child, going to sleep,my parent=%d
    ", getppid());
                        sleep(10);
                        printf("----child die----
    ");
                } else if(pid > 0) {
                        while(1){
                                printf("I am parent, pid=%d, myson=%d
    ", getpid(), pid);
                                sleep(1);
                        }
                } else {
                        perror("fork error");
                        exit(1);
                }
        
                return 0;
        }

    ps aux 查询结果如下:
    root 3230 0.0 0.0 4216 352 pts/0 S+ 17:36 0:00 ./zombie.out
    root 3231 0.0 0.0 0 0 pts/0 Z+ 17:36 0:00 [zombie.out] <defunct>--僵尸进程

    wait函数
    一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:
    如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用
    wait或者waitpid获取这些信息,然后彻底清除掉这个进程。我们知道一个进程的退出状态我们可以在shell中用特殊变量$?
    查看,因为shell是它的父进程,当它终止时shell调用wait或waitpid得到它的退出状态同时彻底清除这个进程。

    父进程调用wait函数可以回收子进程终止信息,该函数有三个功能:
    1).阻塞等待子进程退出
    2).回收子进程残留资源
    3).获取子进程结束状态(退出原因)
    pid_t wait(int *status);
    成功:清理掉子进程ID;
    失败:-1(没有子进程)

    当进程终止时,操作系统的隐式回收机制会做如下操作:
    1).关闭所有的文件描述符
    2).释放用户空间分配的内存
    内核的PCB仍存在,其中保存该进程的退出状态。(正常终止-->退出值,异常终止-->终止信号)

    可使用wait函数传出参数status来保存进程的退出状态。借助宏函数来进一步判断进程终止的具体原因。
    宏函数可分为三组:
    1).WIFEXITED(status) 为非0 -->进程正常结束
    WEXITSTATUS(status) 如上宏为真,使用此宏-->获取进程退出状态(exit的参数)

    2).WIFSIGNALED(status) 为非0 -->进程异常终止
    WTERMSIG(status) 如上宏为真,使用此宏-->取得进程终止的那个信号的编号(kill的参数)

    wait第一版:

        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/wait.h>
        
        int main(void)
        {
            pid_t pid, wpid;
            pid = fork();
        
            if(pid == 0) {
                printf("----child, going to sleep,my parent=%d
    ", getppid());
                sleep(10);
                printf("----child die----
    ");
            } else if(pid > 0) {
                wpid = wait(NULL);
                if(wpid == -1){
                    perror("wait error");
                    exit(1);
                }
                
                while(1){
                    printf("I am parent, pid=%d, myson=%d
    ", getpid(), pid);
                    sleep(1);
                }
            } else {
                perror("fork error");
                exit(1);
            }
        
            return 0;
        }

    wait使用宏版:

        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/wait.h>
        
        int main(void)
        {
            pid_t pid, wpid;
            int status;
            pid = fork();
        
            if(pid == 0) {            
                printf("----child, going to sleep,my parent=%d
    ", getppid());
                sleep(20);
                printf("----child die----
    ");
                return 100;
            } else if(pid > 0) {
                wpid = wait(&status);
                if(wpid == -1){
                    perror("wait error");
                    exit(1);
                }
                if(WIFEXITED(status)) {
                    printf("child exit with %d
    ",WEXITSTATUS(status));
                }
                if(WIFSIGNALED(status)) {
                    printf("child killed by %d
    ",WTERMSIG(status));
                }
                
                while(1){
                    printf("I am parent, pid=%d, myson=%d
    ", getpid(), pid);
                    sleep(1);
                }
            } else {
                perror("fork error");
                exit(1);
            }
        
            return 0;
        }

    gcc abnor.c -o abnor.out 测试段错误和浮点错误

        int main(void){
        char *p = "test of wait abnormally
    ";
        //p[0] = 'h';//测试段错误
        int a = 5/0;//测试浮点错误
        return 65;
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <sys/wait.h>
        
        int main(void)
        {
            pid_t pid, wpid;
            int status;
            pid = fork();
        
            if(pid == 0) {        
                execl("abnor.out", "abnor.out", NULL);
                printf("----child, going to sleep,my parent=%d
    ", getppid());
                sleep(20);
                printf("----child die----
    ");
                return 100;
            } else if(pid > 0) {
                wpid = wait(&status);
                if(wpid == -1){
                    perror("wait error");
                    exit(1);
                }
                if(WIFEXITED(status)) {
                    printf("child exit with %d
    ",WEXITSTATUS(status));
                }
                if(WIFSIGNALED(status)) {
                    printf("child killed by %d
    ",WTERMSIG(status));
                }
                
                while(1){
                    printf("I am parent, pid=%d, myson=%d
    ", getpid(), pid);
                    sleep(1);
                }
            } else {
                perror("fork error");
                exit(1);
            }
        
            return 0;
        }

    根据kill -l找到对应的信号

    waitpid函数
    可以指定pid进程清理,可以不阻塞。
    pid_t waitpid(pid_t pid, int *status, int options);
    成功:返回清理掉的子进程ID; 失败:-1(无子进程结束)
    特殊参数和返回值情况:
    参数1 pid:
    >0 回收指定ID的子进程
    -1 回收任意子进程(相当于wait)
    0 回收和当前调用waitpid一个组的所有子进程
    <-1回收指定进程组内的任意子进程
    参数2 status

    参数3 设置为WNOHANG,非阻塞回收(轮询)
    设置为0,父进程阻塞等待子进程执行完,阻塞回收
    返回值: 成功:pid
    失败:-1
    返回0:参数3设置为WNOHANG,且子进程正在运行

    注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。

  • 相关阅读:
    Ymodem协议(参考STM32)
    嵌入式 Linux 对内存的直接读写(devmem)
    四则运算表达式分解,前中后缀表达式(栈的应用)
    I2C总线的仲裁机制
    用例图【图7】--☆
    顺序图【6】--☆☆
    部署图【图5】--☆
    组件图【图4】--☆
    活动图、泳道【图1】--☆☆
    Mybatis增删改查(CURD)
  • 原文地址:https://www.cnblogs.com/zheaven/p/14262367.html
Copyright © 2011-2022 走看看