进程组与作业、会话之间的关系

进程与作业控制详解
本文详细介绍了进程组、作业和会话的概念及其相互关系,解释了如何通过终端控制进程,并探讨了守护进程的创建和特性。

一、进程组、作业、会话 1.进程组(process group) 每个进程除了有一个进程ID(保存在PCB当中),还属于一个进程组。进程组由一个或多个进程组成,通常和一个作业相关联,可以接收来自同一终端的各种信号。每个进程组有一个唯一的进程组ID。 每个进程组都有一个组长进程,组长进程的ID等于组ID。 组长进程可以组建一个进程组。只要进程组中有一个进程存在,这个进程组就存在。 2.作业(job) 当命令行上运行一个进程时,就会变成一个作业,这个作业可能是一个进程,也可能是多个进程。 shall有且只能运行一个前台作业,当前台有作业时,就不会运行其他作业,shell在后台运行(此时不能接收指令),当作业终止,shall被提到前台,可以接收指令 shell分前后台来控制的不是进程而是作业或者进程组。一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成。shell可以运行一个前台作业和任意多个后台作业。(作业控制) *作业和进程组区别:如果作业中某个进程又创建子进程(fork),则子进程不属于作业,属于进程组。一旦前台作业运行结束,shell就把自己提到前台,若原来前台进程还在(子进程还没终止 ),则自动变为后台进程组 3.会话(session ) 会话是一个或多个进程组的集合。一个会话可以有一个控制终端。建立与控制终端连接的会话首进程被称为控制进程(一般bash就是控制进程)。一个会话中几个进程组可被分为一个前台进程组和一个或多个后台进程组。 一个会话中,应该包括控制进程(会话首进程)、一个前台进程组和任意后台进程组。 ctrl+c(SIGINT信号),ctrl+(SIGQUOT),ctrl+Z(SIGTSTP)内核发送相应的信号给前台进程组中所有进程。 切换用户就是当前会话首进程起新进程组,每次su会加载新bash,每次打开终端也会新起一个bash

二、终端 1.基本概念 用户通过登录系统后获得一个shell进程,这个终端称为shell进程的控制终端,控制终端是保存在PCB中的信息。fork时会复制PCB中的信息,所以由shell进程启动的其他进程的控制终端也是这个终端。默认情况下(未重定向)每个进程的标准输入、标准输出和标准作物都指向控制终端。在控制终端输入一些特殊的控制键可给前台进程发送信号(ctrl+c 、ctrl+Z等) 每个进程都可通过一个特殊的设备文件/dev/tty访问控制终端例: 1.一个进程要访问它的控制终端可以通过dev/tty也可以通过该终端设备对应的设备文件来访问 2.ttyname函数可由文件描述符查看对应文件名。该文件描述符必须指向一个终端设备而不是任意文件。

2.终端的登陆 一个pc通常只有一套键盘和显示其,也就是只有一套终端设备,但可以通过Ctrl+Alt+F1~F6 切换到6个字符终端,相当于有6套虚拟终端设备,它们共同用一套物理终端设备,对应的设备文件为/dev/tty1~/dev/tty6 登陆过程: 1.系统启动,init进程根据配置文件确定打开那些终端 2.getty根据命令行参数打开终端设备作为它的控制终端,把文件描述符0、1、2指向控制终端,然后提示用户输入账号,当用户账号输后,getty任务完成。 3.lofin程序提示用户输入密码(输入密码期间关闭终端回显),然后验证账号密码的正确性。若密码错误,login进程终止,init重新fork/exec一个getty,继续步骤2;若正确,login设置一些环境变量,设置当前工作目录为该用户主目录,然后执行shell 4.execl函数启动bash,在bash前加“-”表示bash作为shell启动,执行shell脚本 *getty->exec->login->execl->bash

三、作业控制 1.Session与进程组 shell可以同时运行一个 作业/进程组 和任意多个后台 作业/进程组,这称为作业控制。一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成。例: 启动5个进程: proc1 | proc2 &proc1 | proc2 &proc3 | proc4 | proc5 其中:1.proc1和proc2属于同一个后台进程组(&表示后台运行),proc3、proc4、proc5属于同一个前台进程组。shell进程属于一个单独的进程组。 2.这些进程控制终端相同,属于同一个session。 3.当用户在控制终端输入特殊的控制键(ctrl+c等),内核发送相应的信号给前台进程。

2.从session核进程组的角度看终端过程 ①getty或telnetd进程打开终端设备之前调用setsid创建一个新session(该进程为session leader),该进程的id可以看做session的id,然后该进程打开终端设备作为这个session中所有进程的控制终端。。 ②登陆时,getty/telnetd变为login,然后变为shell,但仍是同一个进程,仍是session leader。 ③shell进程fork子进程(子进程和shell的session、进程组、控制终端相同),shell调用setgid函数将作业中某个子进程指定为一个新进程组leader,然后将该作业中其他子进程也转移到这个进程组中。 若进程组需要在前台运行,就调用tcsetgrp函数将它设置为前台进程组。由于一个session只能有一个前台进程组,所以shell所在的进程组自动变为后台进程组。shell调用wait等待前台进程运行结束,一旦结束shell调用tcsetgrp函数将自己提到前台继续接受命令。 注意:若前台进程某个进程又fork出子进程, 这个子进程 虽然属于这个进程组但是不属于这个作业,shell不知道子进程存在,所以不会调用wait等待它结束。所以前台作业运行结束,shell自动到前台,这个子进程若没有终止,则自动变为后台。

3.与作业控制相关的信号 cat cat指令读标准输入(终端输入) jobs 查看当前有哪些作业

fg 进程号 将某个作业提到前台运行,若改作业的进程组正在后台运行则提至前台运行,若该作业处于停止状态,则给该进程组每个进程发送SIGCONT信号使它继续运行

bg 让某个停止的作业在后台继续运行,也需要该作业的进程组每个进程发送SIGCONT信号,cat继续运行,但是cat需要读终端输入,然而后台不能读所以收到SIGTTIN信号终止

*注意:kill命令可以给一个停止的进程发SIGTERM信号,这个信号不会立即处理,而是等进程准备继续运行之前处理,默认动作是终止。若给一个停止的信号发SIGKILL信号则立即处理 SIGKILL信号即不能被阻塞也不能被忽略,也不能自定义捕捉函数,只能立即处理,SIGSTOP信号同STOPKILL信号。

四、守护进程 1.概要 守护进程也成精灵进程(daemon),是指在后台运行的一种特殊进程。独立于控制终端并周期性的执行某种任务或等待处理某些发生的事件。 linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能喝用户交互,其他进程都是在用户登录或运行程序时创建,在运行结束或者用户注销时终止,但系统服务进程不受用户注销影响,它们一直运行,这种进程就是守护进程。 ps axj 可以查看系统中的进程 a表示不仅列出当前用户进程,也列出所有其他用户的进程 x表示不仅列出控制终端的进程,也列出所有无控制终端的进程 j表示列出与作业控制相关的信息

\

上图中 ①TPGID为-1表示没有控制终端的进程,即守护进程 ②COMMAND用[]括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,所以没有程序文件名和指令行 ③COMMAND中k开头的表示kernel ④守护进程通常以d结尾(daemon) 2.创建守护进程 创建守护进程: 1.调用umask将文件模式创建屏蔽字设置为0 2.调用fork,父进程退出(原因:①若该守护进程作为一条简单的shell命令启动,则父进程终止使shell认为该命令执行完毕。②保证子进程不是进程组的组长进程) 3.调用setsid创建一个新会话(①调用进程成为新会话首进程。②调用进程称为组长进程。③调用进程没有控制终端) 4.当前共工作目录改为根目录 5.关不不需要的文件描述符 6.忽略SIGCHLD信号。 创建守护进程最关键的是调setsid函数创建新session,并成为session leader

函数调用成功返回新创建的session的id(即当前进程的id),出错返回-1. 当调用这个函数之前,当前进程不允许是进程组的leader,否则返回-1.(先fork再调用setsid,fork创建的子进程和父进程在同一个进程组中,leader一般是该组的第一个进程,所以这个子进程一定不是leader) 调用成功: ①创建一个新session,当前进程称为session leader,当前进程id是session id ②创建一个新的进程组,当前进程成为进程leader,当前进程id就是进程组id ③若当前进程原本有一个控制终端,则它失去这个控制终端(原来的控制终端仍打开,仍可以读写但是只是一个普通的打开文件而不是控制终端),成为一个没有控制终端的进程。

<think>好的,用户现在想了解进程组会话之间的区别联系。我需要仔细分析他们提供的引用内容,并结合之前的回答来构建一个清晰的解释。首先,我应该回顾之前给出的关于进程组会话的说明,确保这次回答保持一致,同时更深入地结合用户提供的引用内容。 首先,用户引用了多个来源,其中提到会话进程组的集合,每个会话有唯一的SID,通常由创建会话的进程的PID决定。而进程组是共享同一控制终端的进程集合,用于信号广播和作业控制。两者的核心区别在于层级结构:会话包含多个进程组,而进程组包含多个进程。联系方面,进程组属于会话会话管理进程组,比如控制终端和信号传递。 接下来,我需要确定如何组织这些信息。可能的结构是先讲区别,再讲联系,或者分点列出。根据用户之前的示例,分点结构比较合适。需要确保每个点都明确区分和联系,并引用提供的资料来支持。例如,引用[1]和[2]提到会话进程组的集合,而引用[3]和[5]则说明进程组用于作业控制,属于会话的一部分。 还要注意用户可能需要的实际例子或应用场景,比如会话如何管理前台和后台进程组,或者进程组如何接收信号。例如,当用户输入Ctrl+C时,信号会发送到前台进程组,这是由会话管理的。引用[3]提到这一点,可以结合到回答中。 另外,用户提供的引用[4]提到创建新会话需要调用setsid,通常由守护进程使用。这可能会话的独立性有关,这也是一个重要的联系点。会话允许进程组脱离控制终端,成为守护进程,这部分可以在联系中说明。 需要确保术语正确,比如SID、PGID、控制终端等。同时,检查是否有权限或创建过程的相关注意事项,比如只有组长进程才能创建新进程组,或者创建会话需要fork和setsid的组合,这在引用[4]中提到。 最后,用户可能希望了解实际应用,比如为什么需要会话进程组,或者它们如何影响进程管理。结合这些实际例子能帮助用户更好地理解概念。例如,在Shell中,每个作业进程组)属于同一个会话,用户可以通过会话管理多个作业的前后台切换。 总结,我需要将区别和联系分点列出,结合引用内容中的定义、结构、功能、生命周期、标识符等方面,同时加入实际例子和操作命令,如使用ps查看PGID和SID,或者如何发送信号到进程组。这样用户不仅能理解理论,还能看到实际应用。</think>#### 进程组会话的区别联系详解 --- ##### 一、核心区别 | **特征** | **进程组** | **会话** | |-------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| | **定义** | 共享同一控制终端的进程集合(作业控制的最小单位)[^1] | 一个或多个进程组的容器,管理进程组的生命周期和终端交互[^2] | | **层级关系** | 进程的直接管理单位 | 更高层级的抽象,包含多个进程组(如:Shell会话管理多个后台/前台作业)[^3] | | **标识符** | PGID(进程组ID),等于组长进程的PID | SID(会话ID),等于会话首进程的PID[^4] | | **控制终端关联** | 继承所属会话的控制终端 | 唯一拥有控制终端的权限(若存在),决定信号传递目标(如`CTRL+C`发送给前台进程组)[^3][^5] | | **生命周期** | 持续到最后一个进程终止或离开 | 持续到最后一个进程组终止,或控制终端关闭[^2] | | **典型操作** | `setpgid()`创建/修改组,`kill(-PGID)`发送信号到整个组 | `setsid()`创建新会话,`ioctl()`管理控制终端 | --- ##### 二、核心联系 1. **包含关系** $$ \text{会话} \supset \{\text{进程组}_1, \text{进程组}_2, ...\} \supset \{\text{进程}_1, \text{进程}_2, ...\} $$ - 每个进程必属于一个进程组,每个进程组必属于一个会话[^1] - 示例:Shell启动的多个管道命令(如`ls | grep txt | wc -l`)形成一个进程组,整个Shell会话可能包含多个此类进程组[^3] 2. **信号传递机制** - 会话通过控制终端决定信号接收者: - `CTRL+C`(`SIGINT`)仅发送给**前台进程组** - 后台进程组需通过`kill -SIGTERM -<PGID>`手动发送信号[^1] - 示例:终止整个会话会关闭所有关联的进程组(如SSH连接断开时触发的`SIGHUP`)[^5] 3. **资源管理** - 会话统一管理进程组的终端I/O资源(如标准输入/输出) - 进程组共享会话的**控制终端**和**工作目录**(除非显式修改)[^2] 4. **守护进程依赖** - 创建守护进程需脱离原会话: ```c pid_t pid = fork(); if (pid == 0) { setsid(); // 子进程创建新会话,成为会话首进程 setpgid(0, 0); // 可选:显式创建进程组 // 后续守护进程逻辑... } ``` - 此操作使进程组会话解耦原终端,避免受用户注销影响[^4] --- ##### 三、实际应用场景 1. **Shell作业控制** - 前台作业:`./server`(独占终端输入) - 后台作业:`./worker &`(属于同一会话的不同进程组) - 切换命令:`fg %1`将进程组1调至前台[^3] 2. **系统服务管理** - 通过会话隔离服务进程(如`systemd`为每个服务创建独立会话) - 使用`systemctl kill --session <SID>`终止整个服务会话[^5] 3. **调试分析** - 查看会话进程组关系: ```bash ps -o pid,pgid,sid,tty,comm ``` 输出示例: ``` PID PGID SID TT COMMAND 1001 1001 1001 pts/0 bash 2002 2002 1001 pts/0 ./server 3003 3003 1001 pts/0 ./worker ``` --- ##### 四、对比总结表 | **操作/属性** | **进程组** | **会话** | |---------------------|---------------------------------------|---------------------------------------| | 创建方式 | `setpgid()` | `setsid()` | | 标识符来源 | 组长进程PID | 会话首进程PID | | 信号广播范围 | 组内所有进程 | 会话内所有进程组(通过终端间接控制) | | 典型生命周期触发点 | 最后一个进程退出 | 控制终端关闭或会话首进程终止 | | 权限限制 | 只能修改自己或子进程的PGID[^1] | 创建新会话需无控制终端(守护进程要求)[^4] | --- #### 相关问题 1. 如何通过`ps`命令快速区分进程所属的会话进程组? 2. 为什么在创建守护进程时需要先调用`fork()`再调用`setsid()`? 3. 会话Linux终端(TTY)的具体交互机制是怎样的? --- : 进程组的定义操作权限 [^2]: 会话的生命周期控制终端 [^3]: 前台/后台进程组的信号传递机制 [^4]: 守护进程会话创建的关联 [^5]: 会话在系统服务管理中的应用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值