Linux---进程组、作业、会话

1.进程组

每个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。通常,它们与同一作业相关联,可以接收来自同一终端的各种信号。每个进程组有一个唯一的进程组ID,可以有一个组长进程。

组长进程的标识是,其进程组ID等于其进程ID。组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要某个进程组中存在一个进程,则该进程就存在,这与组长进程是否终止无关。

上面的概念可能有点抽象,现在我们来看一个例子。
比如,现在有一个学生是1号,将它分配到1班,因为他是班里的第一个学生,所以他就是这个班的组长(这里组长最大),即组长进程,1班是一个进程组。随后班里来了2号、3号 ……学生,这时1号学生即组长转学了,但是1班还在,只要班里还剩一名学生,1班就一直在。如果所有的学生都转学了,这个1班也就不复存在了。

Linux下的实例:

这里写图片描述

我们用 ps 选项可以看到有 5873、5874、5875三个进程,他们同属于 5873 这个进程组,组长是 5873, 组长进程的ID即为进程组ID。
我们用 kill -9 杀掉组长进程后,发现这个进程组还存在,即一个进程组中只要有一个进程存在,则该进程就存在,与其组长进程是否终止无关。

2.作业

Shell分前后台来控制的不是进程而是作业(Job)或者进程组。一个作业由多个进程组成,我们可以把它看成是任务,由进程组去完成某个任务。

作业与进程组的区别:如果作业中的某个进程又创建了子进程,则这个子进程不属于作业,属于进程组。

我们在前台新起一个作业,Shell是无法运行的,因为它被挤到了后台。一旦这个作业运行结束,Shell就把自己提到前台(子进程还在,可子进程不属于作业,它就自动变为后台进程组),可以继续接受用户的输入。我们来看一个例子:

#include<stdio.h>
#include<unistd.h>

int main()
{
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return 1;
    }
    else if(pid == 0)//子进程
    {
        while(1)
        {
            printf("child (%d)# I am running!\n",getpid());
            sleep(10);
        }
    }
    else//父进程
    {
        int i = 5;
        while(i)
        {
            printf("parent (%d)# I am going to dead...%d\n",getpid(),i--);
            sleep(1);
        }
    }
    return 0;
}

结果:
这里写图片描述

我们发现,程序跑起来之后,在前台新起了一个作业,包含父子两个进程。
5秒之内,shell无法接受任何命令,说明此时前台作业不是shell。
5秒之后,父进程退出,子进程还在运行,但此时输入命令,shell可以处理,说明此时shell变成了前台作业,而子进程就被自动提到后台。此时他还在一直打印消息,用kill -9 杀掉即可。

Shell分前后台来控制的不是进程而是作业(Job)或者进程组。一个前台作业可以由多个进程组成,一个后台也可以由多个进程组成,Shell可以运行一个前台作业和任意多个后台作业,这称为作业控制。

这里写图片描述
这里我们起了两个作业。
jobs — 查看当前有哪些作业。当我们输入此命令可以看到有两个作业。

fg — 将某个作业提至前台运行,如果该作业的进程组正在后台运行则提至前台运行,如果该作业处于停止状态,则给进程组的每个进程发SIGCONT信号使它继续运行。
这里fg 1表示我们将第1个作业提至前台运行。

Ctrl + z — 向所有前台进程发SIGTSTP信号,该信号默认动作是使进程停止。
然后我们在使用jobs命令时,发现第1个作业变为停止状态.

那它如何继续运行呢?

这里写图片描述
通过 bg 命令。
bg — 可以让某个停止的作业在后台继续运行,通过给该作业的进程组的每个进程发SIGCONT信号。
这时我们再用 jobs 命令,发现第1个作业的状态已经变为 Running 了。

Ctrl-C只能终止前台进程组,那我们该如何杀掉后台进程组呢?
这里写图片描述
先将后台作业提到前台,然后Ctrl + c将其终止。这时Ctrl + c杀掉的不是进程,而是整个作业。

cat 读取标准输入的内容
这里写图片描述

这里写图片描述
我们发现,将cat提到后台,由于cat需要读取标准输入,而后台进程是不能读终端的,因此内核发SIGTTIN信号给进程,该信号默认处理动作是使进程终止。
3.会话

会话是一个或多个进程组的集合。一个会话可以有一个控制终端。这通常是登录到其上的终端设备(在终端登录情况下)或伪终端设备(在网络登录情况下)。
建立与控制终端连接的会话首进程被称为控制进程。一个会话中的进程组可被分为一个前台进程组和多个后台进程组。
所以,一个会话中,应包括控制进程一个前台进程组和任意后台进程组。

新打开一个终端:
这里写图片描述
这里的 sid 即为会话id。
我们发现三个进程都属于同一个进程组(6552),同一个会话(6120)。那这里的6120到底是谁?

这里写图片描述
其实是bash!也就是我们的解释器,会话首进程,而且三个进程的父进程也都是bash。

我们再打开一个终端:
这里写图片描述

这时有两个终端 pts/1 和 pts/2, tty表示终端。

这里写图片描述

发现当你每打开一个终端,也就新建了一个会话。

猜你喜欢

转载自blog.csdn.net/y6_xiamo/article/details/80204398