操作系统------进程组/作业/会话/进程控制

进程组

        在之前进程的概念中,有提到当一个可执行程序运行起来之后会形成一个进程。

        而实际上,当一个程序运行起来后形成的是一个进程组。进程组,顾名思义,就是一个或多个进程的集合。每个进程都有一个唯一的进程组ID。该进程组中的第一个运行起来的进程创建了该进程组,因此该进程为进程组的组长进程。而该进程的进程ID就是该进程组的组ID。

        进程组创建之后,只要进程组中还有一个进程存在,该进程组就存在,与组长进程是否存在无关。比如,当组长进程创建了一个进程组后,之后该进程组中有添加了许多进程,当组长进程退出后,只要还有一个进程存在,该进程就存在。

        代码演示:


        上述实例中:

a:列出所有用户,带控制终端的进程

x:列出当前用户带或不带控制终端的进程

j:表示列出与作业控制相关的信息

        在上述实例中,通过管道连接了三个进程。分别是sleep 1000,sleep 2000,sleep 3000。这三个进程同属一个进程组。这三个进程各有一个进程ID:3048,3049,3050.。同时因为进程sleep 1000先运行,所以由该进程创建一个进程组,该进程组的组ID等于该进程的PID:3048。

扫描二维码关注公众号,回复: 867121 查看本文章

        当用kill杀死组长进程后,我们发现组长进程已不存在,但该进程组还在。

作业

        当一个进程运行起来形成一个进程组之后,该进程组是为了完成某一任务的,可以将该任务称为一项作业。可以说,一个进程组是与一项作业相对应的。所以说,shell在前后台控制的是一项作业或一个进程组而不是一个进程。一个进程组有多个进程组成,所以一项作业也由多个进程组成。

        shell可以运行一个前台作业及多个后台作业,这称为作业控制。

        作业与进程的区别在于,如果作业中的某个进程创建了子进程,该子进程属于该进程组,而不属于该作业。

        当前台没有作业在运行时,shell在前台运行。当在前台运行一项作业后(包含进程1,2),shell被提到后台。此时,shell便不能接收其他用户输入的命令了。在前台作业运行过程中,进程1又创建了一个子进程3。此时该进程3与进程1,2同属一个进程组,但进程3不属于该前台作业。当进程1,2退出,但进程3还没退出时,表示前台作业执行结束,所以shell又被提到前台,可以接受用户输入的命令了。而进程3所在的进程组还存在,则它自动变为后台进程组,它所对应的作业被提到了后台继续运行。

        代码演示:

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

int main()
{
    pid_t pid = fork();
    if(pid < 0)
    {   
        perror("fork error");
        exit(1);
    }   
    else if(pid > 0)//father
    {   
        int i = 5;//5s后父进程运行结束
        while(i)
        {   
            i--;
            printf("i am father,pid : %d\n",getpid());
            sleep(1);
        }   
    }   
    else//child
    {   
        while(1)//子进程一直运行                                                                                                      
        {
            printf("i am child,pid: %d\n",getpid());
            sleep(1);
        }
    }   
    return 0;
}

        运行结果如下:


        在上述结果中,当程序运行起来后,在前台启动了一项作业。因为该作业在前台运行,shell被提到了后台,所以不接受用户输入的命令。因此,当输入ls之后,并没有显示出结果。该前台作业中只有一个进程,在该进程中又创建了一个子进程。父进程5s后退出,子进程一直在运行。因为子进程不属于前台作业,所以父进程退出后,前台作业执行完毕,shell重新回到前台,将ls的结果显示出来。子进程所属的进程组被提到后台继续运行。此时shell在前台,所以可以接受用户输入的命令,用kill命令将子进程杀死。所以子进程所属的后台作业也被终止。

        注意:后台作业不能接收用户输入的命令即不能使用标准输入接收命令,但可以输出到屏幕上即可以使用标准输出或标准错误。

会话

        会话是一个或多个进程组的集合。一个会话可以有一个控制终端。通常是登录在其上的终端设备或伪终端设备(在网络登录情况下:Xshell等)。

        建立与控制终端连接的会话首进程称为控制进程。控制进程自成一项作业或一个进程组。

        所以,一个会话包括一个控制进程,一个前台作业和多个后台作业。

        当新打开一个终端,会创建一个会话。同时会有一个会话首进程(控制进程)将该会话与控制终端相连接。此后,在该会话中创建的进程在向终端打印内容时,都会打印到与控制进程相连接的终端下。

        演示如下:


        首先,打开一个终端,在该终端下运行2个进程组:1000 | 2000 和3000 | 4000。

        上图中SID表示会话ID,我们发现两个进程组的会话ID均为3406,即这两个进程组同属于一个会话,与该会话相连接的控制终端是:pts/0。且这两个进程组中的进程的父进程ID均为3406.

        查看后,发现3406其实是bash。在这里,bash充当3个角色:

1. 各进程的父进程           2. 会话ID与bash相同          3. 会话首进程即控制进程(默认为bash)

        kill命令将bash杀死后,即杀死控制进程后,该会话与控制终端pts/0失去连接,也就是该会话没有控制终端了。上图显示,杀死bash之后,又进入了一个新的会话或新的控制终端。

        在新的控制终端上创建一个进程5000。查看后,发现该进程所属的会话ID为3450,与该会话连接的控制终端为pts/1。且上面两个进程组中进程因为父进程bsah被杀死,所以都变成了孤儿进程被1号进程收养。它们所属的会话失去了控制终端pts/0,变成了?。但是该会话还存在,因为会话ID仍为3406。

        注意:杀死话首进程只是与终端失去连接,并不等于杀死会话,要杀死一个会话,要通过注销的方式进程。

                   话首进程自成一个作业或进程组。

        因此,一个进程的PCB中还包含以下内容:


作业控制

        前面有提到,shell可以同时运行一个前台作业和多个后台作业,就称为作业控制。

1. 下面介绍有关作业操作的相关命令

jobs:显示当前终端下的进程组或作业

fg 作业号:将后台作业提到前台

bg 作业号:使处于stopped状态的进程变为Running状态。

        演示如下:


        首先,在后台运行两项作业,用jobs查看,作业号分别是1,2。

        然后,用fg将作业1提到前台,此时作业1便在前台运行。ctrl+z将作业1再提到后台。因为ctrl+z使进程处于睡眠状态,而前台作业是不能停的。一旦前台作业停止(没有退出),就会被提到后台。

        用bg将处于stopped状态的作业1转为Running状态。可以看到作业1继续在后台开始运行了。

        我们知道,由键盘输入的信号只能发送给前台进程。当想杀死具有多个进程的后台作业时,如果用kill命令过于复杂。此时,可以将后台作业提到前台,在ctrl+c直接杀掉即可。

        注意:ctrl+z杀死的是整个前台进程组。而不是单个进程。

2. 下面介绍与作业控制相关的信号

        通过下图中的代码来演示信号的发送过程:


(1)在后台运行cat命令,因为cat命令需要读取标准输入。但后台作业又不能使用标准输入,所以cat被提到后台后,为解决二者之间的矛盾,内核会自动向cat进程发送SIGTTIN信号,使进程处于Stopped状态。

(2)fg将cat作业提到前台。如果该作业处于停止状态,就发送SIGCOUNT信号来唤醒它,使其处于Running状态,此时cat便可以正常的执行了

(3)ctrl+z向cat作业发送SIGTSTP信号,使该作业处于Stopped状态,因此cat作业又被提到后台。

(4)bg命令向作业发送SIGCOUNT信号将处于Stopped状态的作业唤醒使其处于Running状态。但是,因为cat作业主要读取标准输入,而后台作业又不能读取标准输入。所以,此时,在bg发送SIGCOUNT命令之后,内核又会发送SIGTTIN信号给cat作业,使其继续处于Stopped状态。

(5)当用kill命令向cat作业发送15号信号时,因为cat处于后台,所以接收不到该信号,当重新回到前台后,会处理该信号,使cat作业终止。











猜你喜欢

转载自blog.csdn.net/sandmm112/article/details/80102449