精华内容
下载资源
问答
  • 孤儿进程

    2021-01-04 16:16:25
    父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫作孤儿进程 Linux系统避免存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程

    父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫作孤儿进程
    Linux系统避免存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程

    展开全文
  • 孤儿进程 正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程...

    孤儿进程

    正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

    解释:

      孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

    孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

    孤儿进程测试如下:

      1 #include<stdio.h>                                                           
      2 #include<stdlib.h>
      3 #include<errno.h>
      4 #include<unistd.h>
      5 
      6 int main()
      7 {
      8         pid_t pid;
      9 
     10         pid=fork();
     11 
     12         if(pid<0)
     13         {
     14                 perror("fork error");
     15                 exit(1);        
     16         }
     17         else if(pid==0)
     18         {
     19                 printf("I am the child process.\n");
     20 
     21                 printf("pid:%d\tppid:%d\n",getpid(),getppid());
     22                 printf("I will sleep five seconds.\n");
     23 
     24                 sleep(5);//让父进程先结束,使得子进程成为孤儿进程
     25                 printf("pid%d\tppid:%d\n",getpid(),getppid());
     26                 printf("child process is exited\n");
     27         
     28         
     29         }
     30         else
     31         {
     32                 printf("I am father process.\n");
     33                 sleep(1);
     34                 printf("father process is exiting\n");
     35         }
     36 return 0;
     37 }                                                                     
    
    

    这里写图片描述

    孤儿进程组

    定义1
    该组中的每个成员的父进程要么是该组的一个成员,要么不是该组所属会话的成员
    定义2
    不是孤儿进程组的条件是,该组中有一个进程,其父进程属于同一会话的另一个组中。
    也就是说,将该父进程终止就能使该进程组成为僵尸进程孤儿进程(感谢网友”hello”的指正)。这个父进程通常是这个进程组的组长进程,因为只有它的父进程在这个进程组外,而其他进程(组长的子进程)的父进程都是组长进程的ID。

    会在后面的学习中补充说明。

    展开全文
  • 72-孤儿进程孤儿进程

    千次阅读 2017-02-26 15:02:51
    本文来谈谈,另一个对立的概念——孤儿进程,以及孤儿进程组。1. 孤独进程如果一个进程,它的父进程先终止了,则该进程成为孤儿进程。此后,该进程的父进程变为 1 号 init 进程。下面的代码可以产生一个孤儿进程。...

    之前有学习过僵尸进程,它指的是“未老先衰”的子进程先于父进程去逝,而父进程未对它进行回收(wait)所产生的。

    本文来谈谈,另一个对立的概念——孤儿进程,以及孤儿进程组。

    1. 孤儿进程

    如果一个进程,它的父进程先终止了,则该进程成为孤儿进程。此后,该进程的父进程变为 1 号 init 进程。

    下面的代码可以产生一个孤儿进程。

    int main() {
      pid_t pid = fork();
      if (pid == 0) {
         while(1) sleep(1);
      }
      return 0;
    }

    上面的程序运行后,产生一个子进程,进入死循环,而父进程将会退出,此后子进程被 init 进程回收,成为孤儿进程。

    需要注意的是,孤儿进程不像僵尸进程,它是无害的,也不需要回收。

    2. 孤儿进程组

    整个进程组也可以成为孤儿。POSIX.1 将孤儿进程组定义为:

    该进程组的每个成员的父进程要么是该组的成员,要么在其它会话中。

    只要能够满足上面的定义,则此进程组就是孤儿进程组。可能读起来比较拗口,看图 1 中的例子可能会清楚点。


    这里写图片描述
    图 1 非孤儿进程组与孤儿进程组

    图 1 中,按照孤儿进程组的定义,进程组 1 不是孤儿进程组,因为进程组 1 中有一个进程的父进程不属于进程组 1,也不在另一个会话中。

    进程组 2 是孤儿进程组,因为该组中的每个成员满足定义:每个成员的父进程要么在本组中,要么在其它会话中。

    3. 孤儿进程组的特性

    如果一个进程组包含一个或一个以上的停止的进程,当该进程组变成孤儿进程组时,每个处于停止状态的进程会接收到 SIGHUP 挂断信号,紧接着又会收到 SIGCONT 信号。(以上是 APUE 中的解释)

    注意,在英文原版中是这样叙述的:

    Since the process group is orphaned when the parent terminates, and the process group contains a stopped process, POSIX.1 requires that every process in the newly orphaned process group be sent the hang-up signal (SIGHUP) followed by the continue signal (SIGCONT).

    上面的大意是说,刚产生的孤独进程组中的每一个进程,而不是每一个停止的进程,是每一个进程都能收到 SIGHUP 信号。中文翻译版本的确有点坑爹啊!!!

    在 Ubuntu 和 Red Hat 中的测试结果也验证了原版中的解释,如果进程组存在停止状态的进程,当该进程组变成孤儿进程组时,该进程组中所有进程都会收到 SIGHUP 信号。其它系统中并未测试,如果你的结果和此不一样,请在下文留言。

    4. 实验

    下面的程序功能:进程组中存在停止的进程,该进程组成为孤儿进程组后,该进程组所有的进程会收到 SIGHUP 信号。另外,该程序还演示了后台进程组试图读控制终端会产生错误。

    需要注意的是,父进程终止,子进程进入后台进程组。

    • 代码
    // orphan.c
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <errno.h>
    
    void handler(int sig) {
      printf("hello sighup, pid = %d\n", getpid());
    }
    
    void print(char *name) {
      printf("%s: pid = %d, ppid = %d, pgrp = %d, tpgrp = %d\n", 
          name, getpid(), getppid(), getpgid(getpid()), tcgetpgrp(0));
      fflush(stdout);
    }
    
    int main() {
      char c;
      pid_t pid;
      print("parent");
    
      pid = fork();
      if (pid < 0) {
        perror("fork");
      }   
      else if (pid > 0) {
        sleep(5);
      }
      else {
        print("child");
        signal(SIGHUP, handler);
        kill(getpid(), SIGTSTP); // 让子进程暂停
        print("child"); // 如果执行了此行,说明已经收到了 SIGHUP 信号
    
        if (read(STDIN_FILENO, &c, 1) != 1) {
          printf("read error, error number: %d\n", errno);
        }   
        exit(0);
      }
      return 0;
    }
    • 编译和运行
    $ gcc orphan.c
    $ ./orphan
    • 结果


    这里写图片描述
    图2 运行结果

    上面的结果正是预期的。

    程序一开始让父进程打印信息,接着 fork 出子进程,让子进程打印信息,然后子进程进入停止状态。

    等待父进程结束后,子进程所在的组变成了孤儿进程组,同时它也是后台进程组。接着所有子进程会收到 SIGHUP 信号,因为子进程对该信号进行了捕获,信号处理函数向控制终端输出 hello sighup, pid = 3080.

    接下来子进程继续执行 print 向屏幕输出信息,注意此时的前台进程组 tpgrp = 3056,这是 bash 进程所在的进程组 id,也等于 bash 进程的 id.

    最后,子进程试图读控制终端,于是收到 SIGTTIN 信号,read 返回出错,errno 被设置为 5,也就是 EIO,解释如下:

    EIO I/O 错误。当进程位于后台进程组时,还试图从控制终端读,就会产生此错误。

    为了验证其它未停止的进程也能收到信号,你可以多 fork 一个子进程来进行测试。

    5. 总结

    • 理解什么是孤儿进程组
    • 理解进程组中存在和不存在停止的进程的影响

    练习:产生一个孤儿进程组,该进程组中有停止的进程,在程序中捕获 SIGHUP 信号。

    展开全文
  • 这篇文章主要介绍如何fork孤儿进程,同时如何巧妙将孤儿进程PID传递给父进程 什么是孤儿进程  父进程创建子进程后退出,子进程会被init进程认领,因此子进程的ppid会成为init进程的pid,这样创建的子进程就叫做...

    这篇文章主要介绍如何fork孤儿进程,并且管理孤儿进程的生死

    什么是孤儿进程

      父进程创建子进程后退出,子进程会被init进程托管,因此子进程的ppid会成为init进程的pid,这样创建的子进程就叫做孤儿进程。

    创建孤儿进程实例

    #include<stdio.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    int main() 
    {
        // main process
        pid_t child_pid = fork();
        if (child_pid < 0) {
            printf("create child process failed");
        } else if (child_pid == 0) {
            // child process
        } else if (child_pid > 0) {
            // main process
            // 创建child process后父进程退出,
            // 子进程被init进程托管,成为孤儿进程。
            exit(0);
        }  
    }

    管理孤儿进程

      通过上面的例子我们知道,父进程退出后,子进程会被init进程托管,这样的话,如果我们想找到这个孤儿进程并管理它,就比较麻烦。
      首先,要管理这个孤儿进程,在这个例子里,main进程肯定是不能退出的(否则谁来管理呢),必须通过另一个进程来fork出这个孤儿进程:

    #include<stdio.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    int main() 
    {
        // main process
        // "relay process", 中继进程,fork孤儿进程
        // 实现创建孤儿进程并不会使得main进程退出
        pid_t relay_pid = fork();
        if (relay_pid < 0) {
            printf("create relay process failed");
        } else if (relay_pid == 0) {
            // relay process
            // fork另一个子进程并退出
            pid_t orphan_pid = fork();
            if (orphan_pid < 0) {
                printf("create orphan process failed");
            } else if (orphan_pid == 0) {
                // orphan process
            } 
            // relay_process
            // 退出使orphan process成为孤儿进程
            exit(0);
        } 
        // main 进程 
    }

      从上面的例子来看,我们做到了fork出孤儿进程并且主进程没有退出,其实很简单,只要fork另一个子进程来创建这个孤儿进程就可以了。然而上面的例子并没有实现由main进程来管理这个孤儿进程这个功能。有个难点,main进程如果想管理这个孤儿进程的生死,就必须掌握这个孤儿进程的orphan_pid。但是这个orphan_pid只有relay process才能拿得到,并且relay process和main process是跨进程的,如何将orphan_pid给main进程呢?这里就涉及到跨进程通信了,使用pipe,使用共享内存?难免有些大材小用。我们知道,和fork函数一起的,还有个vfork函数,两者的区别如下: 

    1. fork出的子进程拷贝父进程的数据段,代码段
    2. vfork出的子进程与父进程共享数据段
    3. 使用vfork,父进程在子进程调用exec或exit之后才可能被调度运行。

      由于relay进程会在fork出orphan进程后退出,同时vfork也可以使main进程和relay进程共享数据段,因此,main进程想拿到orphan进程的pid也就不是什么难事了,下面来看看终极版本:

    #include<stdio.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    // 全局数据段,使用vfork时被共享
    pid_t orphan_pid;
    
    int main() 
    {
        // main process
        orphan_pid = -1;
        // 使用 vfork代替fork,relay process和
        // main process共享orphan_pid
        pid_t relay_pid = vfork();
        if (relay_pid < 0) {
            printf("create relay process failed");
        } else if (relay_pid == 0) {
            // relay process
            // fork另一个子进程并退出
            orphan_pid = fork();
            if (orphan_pid < 0) {
                printf("create orphan process failed");
            } else if (orphan_pid == 0) {
                // orphan process
            }
            // relay_process
            // 退出使orphan process成为孤儿进程
            exit(0);
        } 
        // main 进程
        // 等待 relay 进程退出再被调度
        printf("orphan pid:%d", orphan_pid);
    
        // 既然获取了orphan_pid,之后就可以在main进程里对这个孤儿进程进行管理了
    }
    展开全文
  • 孤儿进程 概念: 父进程先于子进程退出 子进程没有父进程获取自身的退出状态,也就变成了孤儿进程 但是,所有的孤儿进程都被一号(init)进程所收养,由一号进程作为所有孤儿进程的父进程,负责孤儿进程的资源...
  • 一、孤儿进程组 1. 孤儿进程的定义: 定义1:该进程组的每个成员的父进程要么是该组的成员,要么在其它会话中。 定义2:一个进程不是孤儿进程组的条件是——该组有一个进程,其父进程在属于同一会话的另一个组中...
  • 孤儿进程、僵尸进程

    2020-01-21 10:31:56
    孤儿进程】 产生条件: 父进程先于子进程退出,此时子进程就会成为孤儿进程 特征: 孤儿进程会被系统指定的进程的收养,即系统进程会成为孤儿进程新的父进程 当孤儿进程退出时,‘继父’会处理孤儿进程...
  • 孤儿进程和僵尸进程

    2019-07-16 14:20:50
    title: 孤儿进程和僵尸进程 date: 2019-06-18 18:26:46 tags: - Linux categories: - Linux 孤儿进程和僵尸进程的概念,回收进程资源(wait、waitpid)。 孤儿进程 孤儿进程:父进程先于子进程结束,则子进程程伟孤儿...
  • 孤儿进程:  当父进程A fork方式出子进程 B,一般情况下是父进程的寿命比子进程的长,但是这时候父进程突然停止了。这时候子线程B 就没有了父亲,就由init进程托管(也就是id为1的进程),然后它就成了孤儿进程。...
  • 早就了解孤儿进程与僵尸进程,但仅仅是停留在一知半解的程度,最近正好有空就顺便学习一下,下面这篇文章主要给大家介绍了关于Linux中僵尸进程和孤儿进程的相关资料,文中介绍的非常详细,需要的朋友可以参考下。
  • 僵尸进程和孤儿进程

    2019-11-05 22:03:13
    僵尸进程:进程终止,父进程尚未回收,子进程残留资源(PCB)存放与内核中,变成僵尸进程。...孤儿进程:父进程先于子进程终止,则子进程成为孤儿进程,子进程的父进程成为init进程,成为init进程领养孤儿进程。 ...
  • 僵尸进程 孤儿进程 进程时间

    千次阅读 2020-11-24 22:26:35
    父进程在子进程之前终止:会产生孤儿进程 孤儿进程:父亲死了,我还活着,我成孤儿了 对于父进程已经终止的所有进程,他们的父进程都会改变成init进程.称之为收养 收养的大致过程: 书上原话: 当一个进程终止之后,内核...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,916
精华内容 5,966
关键字:

孤儿进程