在 Linux 系统中,每个进程都拥有唯一的标识符,即进程号(PID,Process ID),并有独特的生命周期。每个进程都有一个父进程,父进程也可能有更上一级的父进程,最终可以追溯到系统的根进程 init,形成一个进程家族树。当子进程结束时,父进程能接收子进程的终止通知并获取其退出状态。
除此之外,Linux 系统中的进程之间还存在其他层次关系,如进程组和会话,它们进一步拓展了进程之间的关系——不局限于独立进程或父子进程关系,还包括进程组和会话等。
1、无关系
两个进程之间没有任何依赖关系,彼此独立运行、互不干扰。这类进程可以单独运行和终止,彼此没有联系。
2、父子进程关系
父子进程关系通过 fork() 系统调用创建。调用 fork() 的进程称为父进程,被创建出来的新进程称为子进程。父进程和子进程可以通过共享部分资源(如文件描述符)协作。
如果父进程在子进程之前终止,子进程会被操作系统的 init 进程(PID 为 1)接管,init 会成为其新父进程,保证子进程状态能及时被处理。
3、进程组
每个进程除了有进程 ID(PID)和父进程 ID(PPID)外,还隶属于一个进程组,其进程组 ID(PGID)标识它所属的进程组。进程组是为了简化多个进程的管理,例如系统需要同时运行并管理多个相关进程时,可将它们归入同一进程组统一控制。
进程组的特点:
- 每个进程必定隶属某个进程组,且只能属于一个进程组。
- 每个进程组有一个组长进程,其进程 ID 就是进程组的 PGID。
- 通过在组长进程 ID 前加负号,可对整组进程执行操作。
- 即使组长进程终止,只要组内仍有其他进程,该进程组依然存在。
- 新创建的进程会继承其父进程的进程组 ID,除非显式改变。
获取进程组 ID 使用 getpgrp() 和 getpgid() 系统调用:
#include
pid_t getpgid(pid_t pid); // 获取指定进程的进程组 ID
pid_t getpgrp(void); // 获取调用进程的进程组 IDgetpgrp() 等价于 getpgid(0),即获取调用进程的进程组 ID。设置通过 setpgid() 系统调用:
#include
int setpgid(pid_t pid, pid_t pgid);setpgid(pid, pgid) 将 pid 指定的进程加入 pgid 进程组;setpgrp() 是 setpgid(0, 0) 的简写,用于创建新的进程组。
4、会话

会话是进程管理的另一层结构,包含一个或多个进程组。
会话与进程组的关系:一个会话可以包含多个进程组;每个会话只能有一个前台进程组,其它为后台进程组;会话的首领是创建该会话的进程,且会话首领也作为新进程组的组长。当用户在某个终端登录时,系统会创建新会话,前台进程组中的进程可接受终端输入和信号(如 Ctrl+C 产生的 SIGINT)。
获取会话 ID 使用 getsid() 系统调用:
#include
pid_t getsid(pid_t pid);若参数 pid 为 0,则返回调用进程的会话 ID。创建新会话使用 setsid():
#include
pid_t setsid(void);调用成功后,setsid() 返回新的会话 ID。
Linux 系统通过进程 ID、父子进程关系、进程组和会话等层次结构,提供了灵活的进程管理方式。进程组简化了对多个相关进程的管理,而会话机制在多终端、多用户环境下起着重要作用。通过系统调用,用户可以精确控制这些进程关系,以实现复杂的进程管理任务。








进程组和会话这段平时很少有人讲清楚,父子、进程组、会话三层关系理顺了。
setsid 把脱离终端讲透了,工作里做服务经常用到。
从 PID 到会话的层级结构梳理得很系统,Linux 进程管理入门好文。