• 进程——wait与waitpid、僵尸进程与孤儿进程


    僵尸进程:子进程终止了,但是父进程没有回收子进程的资源PCB。使其成为僵尸进程

    孤儿进程:父进程先与子进程结束了,使得子进程失去了父进程,这个时候子进程会被1号进程init进程领养,成为孤儿进程

    为了防止上面两种情况,我们应当在父进程结束之前一定要回收子进程的所有资源

    所以出现了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);
    
    
    status是一个传出参数。
    waitpid的pid参数选择:
    < -1 回收指定进程组内的任意子进程
    = -1 回收任意子进程
    = 0  回收和当前调用waitpid一个组的所有子进程
    > 0  回收指定ID的子进程

    一个进程结束的时候,会关闭所有的文件描述符,释放所有的内存空间,但是他的PCB仍然存在,保存着子进程的一些状态信息,如果进程正常退出,保存着正常退出的状态,如果非正常退出,那么保存着是哪个信号导致的该进程退出,父进程可以通过wait和waitpid查看到这些信息,并且彻底清除,我们知道shell是所有进程的父进程,在shell中可以通过 $查看退出状态编号,所以可以通过shell查看并清除,如果一个进程退出,父进程并没有调用wait和waitpid进程清除,那么就产生了僵尸进程,正常情况下,僵尸进程都被父进程清理了

    下面写一个不正常了程序,使得父进程不结束

    #include <unistd.h>
    #include <stdlib.h>
    
    int main(void)
    {
        pid_t pid=fork();
    
        if(pid<0) {
            perror("fork");
            exit(1);
        }
    
        if(pid>0) { /* parent */
            while(1);
        }
    
        /* child */
        return 0;
    }

    上面中,父进程一直处于while(1)循环,使得父进程不退出,下图查看ps aux可以发现父进程状态为R,子进程状态为Z(僵尸态Zombie)

     对于wait或waitpid函数若调用成功则返回清理掉的子进程id若调用出错则返回-1。父进程调用wait或waitpid时可能会出现一下的情况:

    1. 阻塞(如果它的所有子进程都还在运行)。
    2. 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。
    3. 出错立即返回(如果它没有任何子进程)。

     

     上图看到了,wai成功的返回值

    *******************************************************************************************

      对于wait和waitpid两个函数,有所不同的是:

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

    所以,调用wait和waitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进程终止,起到进程间同步的作用。如果参数status不是空指针,则子进程的终止信息通过这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将status参数指定为NULL。 

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <sys/types.h>
     5 
     6 int main(void)
     7 {
     8     pid_t pid,pid_c;
     9 
    10     int n = 10;
    11     pid = fork();
    12 
    13     if(pid > 0 )
    14     {/* in parent */
    15         while(1)
    16         {
    17             printf("I am parent %d
    ",getpid());
    18             //wait是一个阻塞函数,等待回收子进程资源,如果没有子进程,wait返回-1
    19             pid_c = wait(NULL);
    20             printf("wait for child %d
    ",pid_c);
    21             sleep(1);
    22         }
    23     }
    24     else if(pid == 0)
    25     {/* in child */
    26         printf("I am child %d
    ",getpid());
    27         sleep(10);
    28     }
    29 
    30     return 0;
    31 }
    32 
    33 
    34 运行结果:
    35 I am parent 4797
    36 I am child 4798
    37 wait for child 4798
    38 I am parent 4797
    39 wait for child -1
    40 I am parent 4797
    41 wait for child -1
    42 I am parent 4797

    孤儿进程

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main(void)
    {
        pid_t pid;
        int n=10;
        pid = fork();
        if(pid > 0)
        {//创建完之后父进程就退出了
            printf("I am parent
    ");
            exit(0);
        }
        else if(pid == 0)
        {//此时父进程退出,子进程被init程序接管,该进程的父进程号变成1
            while(n--)
            {
                printf("I am %d, my parent is %d
    ",getpid(),getppid());
                sleep(1);
            }
        }
        else
        {
            perror("fork");
            exit(-1);
        }
        return 0;
    }
    
    
    运行结果:
    I am 4813, my parent is 1
    I am 4813, my parent is 1
    I am 4813, my parent is 1
    I am 4813, my parent is 1
    I am 4813, my parent is 1
    I am 4813, my parent is 1

    waitpad

     1 #include <sys/types.h>
     2 #include <sys/wait.h>
     3 #include <unistd.h>
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 
     7 int main(void)
     8 {
     9     pid_t pid;
    10     pid = fork();
    11     if (pid < 0)
    12     {
    13         perror("fork failed");
    14         exit(1);
    15     }
    16 
    17     if (pid == 0)
    18     {//in child
    19         int i;
    20         for (i = 3; i > 0; i--) {
    21             printf("This is the child %d
    ",getpid());
    22             sleep(1);
    23         }
    24         exit(3);//返回3,运行时可以看到
    25         //子进程睡眠3秒之后就退出了
    26     }
    27 
    28     else
    29     {//in parent
    30         int stat_val;
    31         waitpid(pid, &stat_val, 0);//以阻塞方式等待回收子进程,第三个参数0,表示阻塞方式
    32         if (WIFEXITED(stat_val))//正常退出
    33             printf("Child exited with code %d
    ", WEXITSTATUS(stat_val));
    34         else if (WIFSIGNALED(stat_val))//查看被什么信号关闭
    35     printf("Child terminated abnormally, signal %d
    ", WTERMSIG(stat_val));
    36     }
    37     return 0;
    38 }
  • 相关阅读:
    Eclipse运行单个Junit 单元测试
    梯形法求定积分(一)设计梯形法求积分的类模板,梯形法
    写一个顺序表模板,包括顺序表的基本功能,例如查找,插
    对于静态成员函数和静态成员变量的练习
    梯形法求定积分(二)设计一个函数模板,独立的非成员函
    各位高手帮我看看这个清屏程序
    对于静态成员函数和静态成员变量的练习
    二分法的递归算法和迭代算法,算法作为有序表模板类的成
    梯形法求定积分(一)设计梯形法求积分的类模板,梯形法
    二分法的递归算法和迭代算法,算法作为有序表模板类的成
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/6390702.html
Copyright © 2020-2023  润新知