得之我幸 失之我命

when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.

介绍几个进程

进程、僵尸进程、孤儿进程、进程组、前台进程组、后台进程组、孤儿进程组、会话

由于不同的 shell 对使用管道线时创建子进程的顺序不同,故本族谱选用 bash 为例,它是支持作业控制的 shell 的典型代表

文中用到的缩写:

  • PID:进程 ID (由内核根据延迟重用算法生成)
  • PPID:父进程 ID(只能由内核修改)
  • PGID:进程组 ID(子进程、父进程都能修改)
  • SID:会话 ID(进程自身可以修改,但有限制)
  • TPGID:控制终端进程组 ID(由控制终端修改,用于指示当前前台进程组)

难兄难弟:僵尸进程、孤儿进程

僵尸进程

先于父进程终止,但是父进程没有对其进行善后处理(获取终止子进程有关信息,释放它仍占有的资源)。消灭僵尸进程的唯一方法是终止其父进程

孤儿进程

该进程的父进程先于自身终止。其特点是 PPID=1(init 进程的 ID)。一个孤儿进程可以自成孤儿进程组

进程、进程组、会话之间的关系:

总的来说,进程属于一个进程组,进程组属于一个会话,会话可能有也可能没有控制终端

会话

  1. 会话首进程:

    新建会话时,会话中的唯一进程,其 PID=SID。它通常是一个登陆 shell,也可以在成为孤儿进程后调用 setsid() 成为一个新会话

  2. 会话:

    一个或多个进程组的集合。一个登陆 shell 发起的会话,一般由一个会话首进程、一个前台进程组、一个或多个后台进程组组成

进程组

一个或多个进程的集合,进程组属于一个会话。fork() 并不改变进程组 ID

  1. 进程组组长:

    PID 与 PGID 相等的进程。组长可以改变子进程的进程组 ID,使其转移到另一进程组

    例如一个 shell 进程,当使用管道线时,如 echo “hello” | cat,bash 以第一个命令的进程 ID 为该管道线内所有进程设置进程组 ID。此时 echo 和 cat 的进程组 ID 都设置成 echo 的进程 ID

  2. 前台进程组

    该进程组中的进程能够向终端设备进行读、写操作的进程组

    登陆 shell 通过调用 tcsetpgrp() 函数设置前台进程组,该函数将终端设备的 fd(文件描述符)与指定进程组关联。成为前台进程组的进程其 TPGID=PGID,常常可以通过比较他们来判断前后台进程组

  3. 后台进程组

    一个会话中,除前台进程组、会话首进程以外的所有进程组。该进程组中的进程能够向终端设备写,但是当试图读终端设备时,将会收到 SIGTTIN 信号,并停止

    前台进程组 ID 只能有一个,而后台进程组同时可存在多个。后台进程组的 PGID≠TPGID

  4. 孤儿进程组

    定义 1:该组中的每个成员的父进程要么是该组的一个成员,要么不是该组所属会话的成员

    定义 2:不是孤儿进程组的条件是,该组中有一个进程,其父进程属于同一会话的另一个组中

    上图中,按照孤儿进程组的定义,进程组 1 不是孤儿进程组,因为进程组 1 中有一个进程的父进程不属于进程组 1,也不在另一个会话中;进程组 2 是孤儿进程组,因为该组中的每个成员满足定义:每个成员的父进程要么在本组中,要么在其它会话中

either I will find a way, or I will make one.