进程组、作业、会话

本文深入探讨了进程组、作业及会话的概念及其相互间的关系。解释了进程组的构成与特点,作业如何控制一组进程,以及会话如何管理多个进程组。并通过示例展示了这些概念的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进程组、作业、会话

一. 进程组

        我们知道,一个程序运行起来会变成一个进程,每个进程都有一个进程ID,但是除了这个ID,每个进程还属于一个进程组。进程组,顾名思义,是一个或多个进程的集合。每个进程组有一个唯一的进程组ID,且每个进程组都可以有一个组长ID。组长ID的标识是:进程组ID等于其进程ID,组长进程可以创建一个进程组,创建该组中的进程,然后终止。只要进程组中有一个进程存在,该进程组就存在,与进程组的组长进程是否存在无关。我们可以看下面一个例子:


        首先,我们先让一个进程组在后台运行起来,“&”就是表示将进程组放在后台运行。然后用ps axj查看了进程组信息,其中选项的具体含义是:

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

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

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

        我们可以看到,该进程组的组ID是PGID=6634,进程有三个,ID分别为6634、6635、6636,其中进程ID为6634的进程为该进程组的组长进程。我们首先杀死了组长进程,但该进程组依旧运行不受影响;再杀死进程ID为6635的进程,进程组依旧不受影响,直至整个进程组中没有进程了。

二. 作业

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

        shell可以运行一个前台作业和任意多个后台作业,这叫做作业控制。

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

        当前台没有作业运行时,shell在前台运行。当我们在前台运行我们的作业时,shell就被挤到了后台,此时shell接收不到用户输入的命令,即我们在前台输入命令时得不到反应。而一旦作业运行结束,shell就把自己提到前台。要注意的时,在作业运行时,若作业中的进程创建了子进程,该子进程在作业运行结束后还存在,它自动变为后台进程。

实例:

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

int main()
{
    pid_t id = fork();
    if(id < 0)
    {   
        perror("fork");
        return 1;
    }   
    else if(id == 0)//child
    {   
        while(1)
        {   
            printf("child[%d] I am child\n", getpid());
            sleep(1);
        }   
    }   
    else//parent
    {   
        int i = 5;
        while(i--)
        {   
            printf("parent[%d] I am goning to dead after %d\n", getpid(), i); 
            sleep(1);
        }   
    }   
    return 0;
}

        我们分析上述代码,在运行起来形成一个作业。在作业运行过程中,创建了一个子进程,它不属于该作业。所以在5s之后,父进程退出,作业结束,只剩子进程被提回后台运行,shell提回前台。具体运行结果如下:


三. 会话

        会话是一个或多个进程组的结合。一个会话可以有一个控制终端。通常是在登录在其上的终端设备(在终端登录情况下)或伪终端设备(在网络登录情况下:xshell等)。建立与控制终端连接的会话首进程被称为控制进程

        一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包括控制进程(会话首进程)、一个前台进程组、任意个后台进程组。

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

(下图借鉴于博客点击打开链接


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

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

        查看后,我们发现3406其实是bash(简单介绍一下bash表示终端是本地登录的,-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。

注意:

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

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

        所以,一个进程的PCB中还包括:


四. 作业控制

1. 作业控制相关命令

        在前面介绍作业时,提到过“shell可以同时运行一个前台作业和一个或多个后台作业”,这就称为作业控制。下面介绍几个作业控制的相关命令:

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

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

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

这里要注意的是,ctrl+c杀掉的不是进程,而是整个作业。

2. 作业控制相关信号

分析上图过程如下:

(1)首先我们在后台运行cat命令。因为cat命令需要读取标准输入,但后台作业又不能使用标准输入,所以cat被提到后台后,为解决二者之间的矛盾,内核会自动向cat进程发送SIGTTIN信号,使进程处于Stopped状态。所以我们jobs查看时,cat处于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作业回到前台,就会处理该信号,使cat作业终止。




### 进程、作业会话的区别 #### 1. **进程** 进程是操作系统中的基本单位,表示正在运行的程序实例。它是系统资源分配的基本单元,也是处理器调度的核心对象。每个进程都有独立的地址空间、内存、文件描述符其他资源[^1]。 在 Unix 系统中,进程由唯一的 PID(Process ID)标识,并且可以通过 fork exec 系列系统调用来创建新的进程。 #### 2. **作业** 作业通常指代一组相关的进程,这些进程共同完成一项任务。更具体地说,作业是由 shell 组织起来的一个或多个进程的集合[^2]。 例如,在 Shell 中执行一条命令时,Shell 将启动一个新的进程组来运行这条命令及其子进程。这个进程组即构成了一个作业。通过 `jobs` 命令可以在交互式 Shell 下查看当前活动的作业列表。 #### 3. **会话** 会话是一个更高层次的概念,用于组织多个进程组。它是一组共享同一控制终端的进程组的集合[^3]。 - 每个会话有一个唯一标识符 SID(Session ID),并且至少包含一个进程组。 - 控制终端(Controlling Terminal)与会话密切相关,只有会话 leader 才能建立与终端的关联[^1]。 - 当用户登录到系统时,通常会创建一个新的会话,其中可能包含多个作业以及更多的单个进程。 --- ### 关系总结 - **进程**是最基础的单位,负责实际的任务执行。 - 多个相关联的进程组成一个**作业**,便于统一管理操作。 - 而**会话**则进一步将多个作业组合在一起,形成更大的逻辑结构,方便跨作业级别的管理[^2]。 此外还需注意以下几点: - 每个会话最多只能有一个控制终端。 - 如果某个进程脱离了原来的会话并成为孤儿进程,则它可以被 init 或 systemd 收养[^1]。 ```c // 创建新会话的示例代码 #include <unistd.h> int main() { pid_t sid = setsid(); // 创建新会话并返回SID if (sid == -1) { perror("setsid"); return 1; } printf("New session created with SID %d\n", getpid()); return 0; } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值