Linux 进程管理进阶:会话、进程组与守护进程实践
在 Linux 的世界里,进程并非孤立存在。当我们执行一条命令或启动一个服务时,这些进程会以**会话(Session)**为'社交圈'、进程组(Process Group)为'小团体'的形式组织起来;而那些在后台默默运行、不受终端影响的守护进程(Daemon),则是系统稳定运行的幕后英雄。
一、会话(Session)
会话可以理解为进程的一个逻辑区域。通常,一个用户登录对应一个会话。每个会话之间是并行的,关闭一个会话不会影响其他会话。在一个会话内部,包含了许多进程。
注意: 我们登录时打开的 Shell(如 bash)进程并不是操作系统的子进程,而是用来解析用户命令给操作系统的应用程序子进程。
二、前/后台进程管理
前台与后台的区别主要取决于谁拥有键盘控制权。例如,Ctrl+C 信号只对当前的前台进程有效。每个会话区只允许存在一个前台进程,其余均为后台进程。
1. 前台切后台
在命令末尾加上 &,进程会被丢到后台运行。
./Ceshi &
此时它变为后台进程,无法直接读取键盘输入。
2. 查看后台进程
执行 jobs 指令即可查看当前会话中的后台作业,最前面的数字是作业编号(Job ID)。
jobs
3. 后台切前台
使用 fg %作业号 可以将后台作业拉回前台运行。
fg %1
4. 暂停与继续
我们可以使用信号来暂停后台进程。例如 SIGSTOP (信号 19) 用于暂停,bg 命令则用于让暂停的后台进程继续运行。
# 暂停
kill -19 %1
# 继续
bg %1
三、进程组与守护进程
1. 查看进程组
一个会话中可以存在多个进程组。相关联的进程集合即为一个进程组。前台进程组是唯一的,但其中可以包含多个进程(例如管道命令 ls | grep | wc)。
进程组的创建者(第一个进程)就是该进程组的组长,其 PID 即为组员的 PGID。组内所有进程都继承组长的 PGID,直到组长退出或进程被迁移。
可以使用以下指令查看详细信息:
ps -efj
-e: 显示系统内所有进程-f: 显示完整信息(UID, PID, PPID 等)-j: 显示作业控制相关信息(PGID, SID)
| 字段 | 含义 | 与进程组的关系 |
|---|---|---|
| PID | 进程 ID | 唯一标识符 |
| PPID | 父进程 ID | 创建该进程的进程 |
| PGID | 进程组 ID | 核心字段!同组进程 PGID 相同 |
| SID | 会话 ID | 所属会话的 ID |
2. 守护进程原理
守护进程是运行在后台的特殊进程,独立于控制终端,不受用户登录或注销的影响。简单来说,原进程 A 由父进程管理,若父进程主动退出,子进程 A 变为孤儿进程,随后通过系统调用脱离原终端/会话,不再接收终端退出时的信号(如 SIGHUP),从而成为守护进程。
3. 如何创建守护进程
创建一个标准的守护进程通常需要遵循以下步骤:
-
创建子进程,父进程退出:确保主进程不占用终端。
pid_t pid = fork(); if (pid > 0) exit(0); // 父进程退出 // 子进程继续执行 -
子进程单独成为会话:使子进程成为会话首进程,脱离原终端。
setsid(); -
忽略挂起信号:防止终端关闭时收到 SIGHUP 信号。
signal(SIGHUP, SIG_IGN); -
切换工作目录:避免占用根文件系统或其他挂载点。
chdir("/"); -
设置文件权限掩码:确保创建的文件和目录拥有最大权限。
umask(0); -
重定向标准输入输出:将日志信息打印到
/dev/null。int fd = open("/dev/null", O_RDWR); if (fd >= 0) { dup2(fd, 0); // stdin dup2(fd, 1); // stdout dup2(fd, 2); // stderr }
遵循以上步骤,即可构建一个基本的守护进程框架。实际开发中还需考虑资源限制、日志记录等更复杂的细节。


