Linux 进程之会话、进程组和控制终端

Posted by KalosAner on February 2, 2025

一、引言

进程组会话控制终端 是 Linux 系统进程管理和作业控制的核心概念。

会话与进程组之间的关系就像是公司与部门之间的关系。

Snipaste_2025-02-21_15-44-05

二、进程组

概念

进程组是由一个或多个相关联的进程组成的集合,主要用于统一管理和控制这些进程。每个进程都有一个进程组 ID(PGID),用于标识其所属的进程组。进程组一般由组长进程创建,进程组 ID 就是组长进程 ID。

进程组有前台进程组和后台进程组。

前台进程组会阻塞控制终端,能够向终端设备进行读、写操作。

后台进程组不能不能向终端进行读操作,只能向终端进行写操作。

销毁

如果进程组组长进程终止,进程组仍然存在直到组内所有进程都结束,并且组长进程终止不会改变进程组的 PGID。

功能

其他进程可以发送信号给整个进程组,从而影响组内的所有进程。

加入

加入进程组有两种方式:

默认加入:当一个进程通过 fork() 创建子进程时,子进程默认继承父进程的进程组 ID(PGID),因此父子进程位于同一个进程组。

主动加入:进程可以通过调用 setpgid()setsid() 系统调用来改变其所属的进程组。setpgid() 可以将进程加入指定的进程组,而 setsid() 则会创建一个新的会话,并将调用进程设置为该会话中新进程组的组长。

常用函数

1
2
3
4
5
// 获取进程组 ID
pid_t getpgrp(void);

// 修改进程组 ID 为 pid,如果 pid == 0,则修改进程组 ID 为调用进程的 ID
int setpgid(pid_t pid, pid_t pgid); 

三、会话

概念

会话是一个或多个进程组的集合,通常由用户通过登录终端启动。创建会话的进程称为会话首领(Session Leader),其进程 ID(PID)即为会话 ID(SID)。会话可以与一个控制终端相关联,负责处理用户的输入输出。

销毁

当用户关闭控制终端时,系统会先该终端关联的会话中的所有前台和后台进程发送 SIGHUP(挂起)信号。默认情况下,这些进程会因接收到 SIGHUP 信号而终止。但如果有进程在接收到 SIGHUP 信号后继续运行(例如,被配置为忽略该信号),那么会话将继续存在,直到最后一个进程结束。

功能

会话的引入主要用来管理与用户交互的环境。

加入

加入会话也有两种方式:

默认加入:当用户登录系统并启动一个 Shell 时,系统会为该登录创建一个新的会话。此后,所有从该 Shell 派生的进程(通过 fork() 创建)默认属于同一会话,继承相同的会话 ID(SID)。

主动加入:进程可以通过调用 setsid() 系统调用创建一个新的会话。调用该函数的进程不能是当前进程组的组长。成功调用后,进程将:

  1. 成为新会话的会话首领,SID 等于其 PID。
  2. 成为新进程组的组长,PGID 等于其 PID。
  3. 脱离原有的控制终端(如果有的话),新会话没有控制终端。

常用函数

1
2
3
4
5
// 获取会话 ID
pid_t getsid(pid_t pid);

// 创建新会话,注意:调用该函数的进程不能是当前进程组的组长。
pid_t setsid(void); 

四、控制终端

控制终端是与会话关联的终端设备,用于处理用户的输入和输出。当用户通过终端登录系统时,系统会为该会话分配一个控制终端。

一个会话只能有一个控制终端。当用户在终端中运行命令时,这些命令所属的进程通常是前台进程组的一部分,可以直接接受用户输入。而使用 & 符号将命令放入后台运行时,相关进程则属于后台进程组。