Linux进程间关系之进程组,作业,会话与作业控制。

来源:互联网 发布:运营商认证数据不正确 编辑:程序博客网 时间:2024/06/03 08:38

本片博客用到的相关指令fg,bg,jobs,ps等可自行查阅。

进程组

每个进程除了有一个进程ID之外还有一个进程组ID。每个进程都属于一个进程组。进程组是一个或多个进程的集合。每个进程都有一个唯一的进程组ID。每个进程都有一个组长进程。
组长进程标志:其所属进程组ID等于其进程ID。
进程组就是进程的集合,这些进程并不是孤立的,他们彼此之间或者存在父子、兄弟关系,或者在功能上有相近的联系。每个进程都有父进程,而所有的进程以init进程为根,形成一个树状结构。
(init 1号进程)
组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要该进程中的任意一个进程存在,则该进程组就存在,与其组长进程是否存在无关。(战斗到最后一个人)

作业

shell分前后台控制的不是进程而是作业(JOB)或者进程组,一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成,一个shell可以同时运行一个前台作业和多个后台作业,这称为作业控制。

但我们想把一个作业放到后台运行时,可以在运行指令的后面加上 “&”,并且系统会返回当前作业的作业号,以及进程的进程ID。
eg:

./a.out &

一个作业可以是一个进程,也可以是几个进程的集合。例如:

  • 单个在后台执行一个a.out:
    这里写图片描述
  • 多个进程的作业,我们通常利用进程管道“|”讲几个进程集合在一起:
    这里写图片描述

我们可以通过jobs指令查看当前运行的作业:

这里写图片描述

我们还可以通过查看他们的进程信息区别他们,执行指令:

ps axj

你会在最后面找到这四个进程:

这里写图片描述

关于会话,我们会在下面谈。注意第一列的父进程ID与第四列的会话ID相同,为5321,5321正好是第一行的/bin/bash进程。你在往上追溯一下bash的父进程以及bash父进程的父进程会发现很多有趣的事情。

作业与进程组区别:(子进程不属于父进程作业)

如果当前作业中的父进程又创建了子进程,父进程与子进程整体属于这个作业,但是子进程单独不属于作业。但是父子进程属于同一个进程组,一旦作业运行结束,shell就会把自己提到前台。若原来父进程创建的子进程还没有结束,将自动变为后台执行。(可能很难理解)

会话

会话是一个或多个进程组的集合。一个会话可以有控制终端。(可以理解为打开一个终端就是建立一次会话)
建立与控制终端连接的会话首进程称为控制进程。(这个控制进程通常为bash)
一个会话的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以会话包括:

  • 控制进程(会话首进程)
  • 一个前台进程组
  • 任意多个后台进程组

作业控制

这里我们细说一下作业控制,它是BSD在1980年左右增加的一个新特性,它允许在一个终端上同时启动多个作业(进程组)。它控制哪一个作业可以访问终端以及哪些作业在后台运行。作业控制要求以下三种要求的支持:

  • 支持作业控制的shell
  • 内核中的终端驱动程序必须支持作业控制
  • 内核必须提供对某些作业控制信号的支持

从shell的角度来讲:一个shell下只能允许同时运行一个前台作业和多个后台作业

当我们没启动一个后台作业,shell就会赋予这个作业一个标识符(作业号),并打印一个或多个进程ID,当作业完成并且键入回车时,shell会通知作业已经完成。
例如:

这里写图片描述

(上面没有通知的原因是为了方便观察我在程序里面写的死循环。)

信号控制

我们还可以通过发信号与前台作业进程交互。当然这些信号只能通过键盘输入字符发起:

  • 中断字符:(一般采用Delete或Ctrl+c产生)产生SIGINT。
  • 退出字符:(一般采用Ctrl+\)产生SIGQUIT。
  • 挂起字符:(一般采用Ctrl+z)产生SIGTSTP。

这里要说明的是,内核只发送信号给所有的前台进程,因为用户在键盘输入的信号只会被前台进程所接受到。

关于输入输出

我们可以在一个shell下同时运行一个前台作业和多个后台作业,当我们向终端输入数据的时候,该由哪一个作业来接受呢?或者说当这些作业需要向屏幕打印数据的时候,又该由哪个作业先打呢?这里必须有点规矩。

  • 只有前台作业可以接受控制终端输入的数据。
    当有后台进程试图读取终端的时候,这也不是一个错误的行为,只是不被允许。如果终端驱动程序检测到有后台作业试图读取,它会向后台作业发送一个特定SIGTTIN,后台作业接受到此信号后,通常会被停止。

例如:
将下列程序放到后台执行:(不断从终端输入读取数据,并显示到屏幕)

#include<stdio.h>#include<stdlib.h>int main(){    char src[100];    while(1)    {        scanf("%s",&src);        printf("%s\n",src);    }    return 0;}

终端驱动程序知道该作业为一个后台作业。并且检测到该程序试图读取标准输入(控制终端)。所以就将SIGINT信号发送给该后台作业,shell检测到进程的状态改变并通知我们。
这里写图片描述

这样我们就会发现此作业无发正常运行。我们可以用fg命令通过作业号将改作业提到前台执行。(原理:将该作业转为前台进程组,并将继续信号(SIGCONT)发送给该进程组)。因为此时该作业在前台执行,所以它可以从标准输入读取数据。

这里写图片描述

  • 后台作业可以向控制终端输出数据,这是一项可以被禁止或允许的选项,后台作业和前台作业可以同时输出到控制终端,当我们不想后台作业输出时,可以使用stty tostop指令禁止后台作业向控制终端写。
0 0
原创粉丝点击