Linux 进程组
每个进程都有一个进程组号 (PGID)
- 进程组:一个或多个进程的集合 (集合中的进程并不孤立)
- 进程组中的进程通常存在父子关系,兄弟关系,或功能相近
进程组可方便进程管理 (如:同时杀死多个进程,发送一个信号给多个进程)
- 每个进程必定属于一个进程组,也只能属于一个进程组
- 进程除了 PID 外,还有 PGID (唯一,但可变)
- 每个进程组有一个进程组长,进程组长的 PID 和 PGID 相同
pid_t getpgrp(void); // 获取当前进程的组标识
pid_t getpgid(pid_t pid); // 获取指定进程的组标识
int setpgid(pid_t pid, pid_t pgid); // 设置进程的组标识
- pid == pgid,将 pid 指定的进程设为组长
- pid == 0,设置当前进程的组标识
- pgid == 0,则将 pid 作为组标识
进程组示例程序
深入理解进程组
进程组长终止,进程组依然存在 (进程组长仅用于创建新进程组)
父进程创建子进程后立即通过 setpgid() 改变其组标识 (PGID)
同时,子进程也需要通过 setpgid() 改变自身组标识 (PGID)
子进程调用 exec()
- 父进程无法通过 setpgid() 改变其组标识 (PGID)
- 只能自身通过 setpgid() 改变其组标识 (PGID)
进程组标识设置技巧
进程组实验
Linux 会话 (session)
用户通过终端登录系统后会产生一个会话
会话是一个或多个进程组的集合
每个会话有一个会话标识 (SID)
- 终端登录后的第一个进程成为会话首进程,通常是一个 shell/bash
- 对于会话首进程 (session leader),其 PID 与 SID 相等
通常情况下,会话与一个终端 (控制终端) 相关联用于执行输入输出操作
- 会话首进程建立与控制终端的连接 (会话首进程又叫控制进程)
- 会话中的进程可分为
- 前台进程组:可接受控制终端中的输入,也可输出数据到控制终端
- 后台进程组:所有进程后台运行,无法接收终端中的输入,但可以输出数据到终端
问题:在终端中输入命令后,发生了什么?
当命令行 (shell) 运行命令后创建一个新的进程组
如果运行的命令中有多个子命令则创建多个进程 (处于新建的进程组中)
命令不带 &
- shell 将新建的进程组设置为前台进程组,并将自己暂时设置为后台进程组
命令中带 &
- shell 将新建的进程组设置为后台进程组,自己依旧是前台进程组
什么是终端进程组标识 (TPGID) ?
标识进程是否处于一个和终端相关的进程组中
前台进程组:TPGID == PGID
后台进程组:TPGID != PGID
若进程和任何终端无关:TPGID == 1
Linux 会话接口
#include <unistd.h>
pid_t getsid(pid_t pid); // 获取指定进程的 SID,(pid == 0) => 当前进程
pid_t setsid(void); // 调用进程不能是进程组长
- 创建新会话,SID == PID,调用进程成为会话首进程
- 创建新进程组,PGID == PID,调用进程成为进程组长
- 调用进程没有控制终端,若调用前关联了控制终端,调用后与控制终端断联