木下~Linux系统编程笔记之进程
摘要:本文系统介绍了Linux进程管理的核心知识。主要内容包括:进程的定义与五大特性(动态性、并发性、独立性、异步性、结构性)、进程三种状态及其转换规则、进程管理命令(ps/kill)、关键概念(父子进程/僵尸进程等)以及进程控制函数(fork/exec/wait等)。重点阐述了进程创建、执行、终止的全生命周期管理,特别强调了僵尸进程的产生原因及解决方案。
·

一、基础认知
1. 系统编程三阶段定位
进程控制承上启下,是系统编程的核心地基,系统编程学习分为三个阶段:
- 应用层接口:标准 IO、文件 IO 基础操作
- 进程与线程:系统资源调度的最小单位,进程间通信
- 网络通信:基于 socket 的 TCP/IP 内核间网络交互
2. 进程核心定义
进程是运行中的程序,是从创建到消亡的完整动态过程,核心由两部分组成:
- 执行程序:待运行的代码逻辑
- 运行数据:分布在四大内存区域(常量区、静态区、栈区、堆区)
3. 进程与程序的核心区别
| 维度 | 进程 | 程序 |
|---|---|---|
| 本质 | 动态运行实体,有完整生命周期 | 静态磁盘文件,持久化存储 |
| 存储 | 运行在系统内存,占用 CPU / 内存资源 | 保存在磁盘,占用磁盘存储空间 |
| 对应关系 | 一个进程仅对应一个程序 | 一个程序可对应多个进程(运行多次创建多个进程) |
二、进程五大核心特性
- 动态性:进程有完整的生命周期(创建→运行→消亡),一次程序运行对应一个独立进程。
- 并发性:同一时间段内,多个进程宏观上同时运行,微观上 CPU 在多进程间快速切换时间片;需区分并行:同一时刻,多核 CPU 上多个进程真正同时运行。
- 独立性:进程是 Linux 系统资源分配与调度的最小单位;每个进程有唯一 PID(类型为 pid_t,无符号整数),同一次开机 PID 不重复,重启后重置。
- 异步性:进程间执行相互制约,执行顺序不可预知,可通过 sleep 等函数控制执行时序。
- 结构性:进程由「PCB(进程控制块)+ 程序 + 数据」组成;PCB 是系统感知进程存在的唯一标志,用于记录进程状态、指令地址、IO 设备信息等,是系统管理进程的核心结构体。
三、进程核心状态与切换规则
1. 三大核心状态
- 就绪态:已获取除 CPU 外的所有资源,等待 CPU 调度即可执行。
- 执行态:获得 CPU 使用权,代码正在 CPU 上执行。
- 阻塞态:因等待某事件(IO 完成、sleep 延时、信号等),主动放弃 CPU,进入挂起状态。
2. 状态切换铁律与合法路径
核心铁律:阻塞态只能先切换到就绪态,不可直接进入执行态。合法切换路径:
- 就绪态 → 执行态:进程抢到 CPU 时间片
- 执行态 → 就绪态:进程时间片用完,被系统剥夺 CPU 使用权
- 执行态 → 阻塞态:进程等待事件,主动放弃 CPU
- 阻塞态 → 就绪态:进程等待的事件已完成,解除阻塞

四、进程管理核心命令
- ps 进程查看命令
ps -aux:查看系统所有进程的详细状态ps -ef:查看进程的父子进程关系(PID/PPID)- STAT 状态标记速记:R (运行)、S (阻塞)、T (暂停)、Z (僵尸)、I (多线程)、+(后台进程组)
- kill 进程终止命令
- 核心用法:
kill -9 PID,-9为强制终止信号,进程不可忽略,是最稳妥的杀进程方式
- 核心用法:
- 终端快捷键
ctrl+c:终止当前前台进程ctrl+z:暂停当前前台进程
- 暂停进程恢复
fg:恢复最近暂停的进程jobs:查看所有暂停进程编号;fg 编号:恢复指定暂停进程
五、进程核心名词解析
- 父子进程:进程间创建与被创建的关系,创建者为父进程,被创建者为子进程;子进程结束需父进程回收资源,否则产生僵尸进程。
- 祖先进程:PID=1 的 init/systemd 进程,由 0 号系统进程创建,是所有用户态进程的根进程,负责收养孤儿进程并回收资源。
- 守护进程:又称精灵进程,是后台运行、独立于控制终端,周期性执行任务 / 等待事件的特殊进程。
- 僵尸进程:子进程已终止,但父进程未调用 wait/waitpid 回收其资源,已消亡却仍占用系统资源的进程;危害:占用 PID 与内存,大量僵尸进程会导致系统无法创建新进程。
- 孤儿进程:子进程未结束,父进程提前终止,失去父进程的子进程;会被 1 号祖先进程收养,最终由 1 号进程回收资源,无系统危害。
六、进程控制核心函数
1. 获取进程 ID
#include <unistd.h>
pid_t getpid(void); // 获取当前进程PID
pid_t getppid(void); // 获取当前进程的父进程PID
要点:无入参,返回值为对应进程号,无失败返回。
2. 运行进程 system ()
#include <stdlib.h>
int system(const char *string);
- 核心功能:创建子进程执行 string 指定的 shell 命令 / 可执行程序,原进程阻塞等待子进程执行完毕。
- 要点:入参为待执行命令字符串;成功返回 0,失败返回非 0 错误码;常用于调用外部程序。
3. 进程替换 exec 函数族
核心常用函数:
#include <unistd.h>
// 需指定程序完整路径
int execl(const char *path, char *arg, ..., NULL);
// 自动从PATH环境变量查找程序,无需完整路径
int execlp(const char *file, char *arg, ..., NULL);
- 核心功能:用指定程序完全替换当前进程,进程 PID 不变,替换成功后,后续代码永不执行。
- 要点:可变参数最后必须以 NULL 结尾;成功无返回,失败返回 - 1;与 system 核心区别:不创建新进程,直接替换原进程。
4.创建进程 fork ()
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
- 核心特性:一次调用,两次返回,调用成功后生成父、子两个独立进程。
- 返回值规则(必记):
- 父进程中:返回新创建子进程的 PID(>0 的整数)
- 子进程中:返回 0
- 创建失败:返回 - 1
- 核心规则:
- 子进程复制父进程的全部用户空间(堆、栈、常量区、静态区、IO 缓冲区),父子进程内存空间完全独立,修改互不影响。
- 子进程仅从 fork () 之后的代码开始执行,fork 前的代码不会重复执行。
- 父进程通常先执行,子进程创建完成后才会争抢 CPU 时间片。
5. 进程销毁 exit () /_exit ()
#include <stdlib.h>
void exit(int status); // 标准退出
#include <unistd.h>
void _exit(int status); // 系统调用退出
- 核心功能:终止当前进程,status 为退出状态码(0 = 正常退出,非 0 = 异常退出)。
- 核心区别(必记):
exit():刷新 IO 缓冲区,关闭所有打开的文件,再终止进程。_exit():直接终止进程,不刷新缓冲区,不处理 IO 操作。
- 补充:exit () 无论在哪个函数调用都会终止整个进程;return 仅在 main 函数中才会终止进程,普通函数中仅退出当前函数。
6. 进程等待 wait () /waitpid ()
核心作用:父进程等待子进程终止,回收子进程资源,从根源避免僵尸进程。
wait()
#include <sys/wait.h>
pid_t wait(int *status);
- 功能:阻塞父进程,直到任意一个子进程终止,回收其资源。
- 参数:status 接收子进程退出状态,不关心可填 NULL。
- 返回值:成功返回终止的子进程 PID,失败返回 - 1。
waitpid()
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
- 功能:可指定等待的子进程,支持阻塞 / 非阻塞模式,灵活性高于 wait ()。
- 参数要点:
- pid:-1 = 等待任意子进程(效果同 wait);>0 = 等待指定 PID 的子进程
- status:接收子进程退出状态,不关心填 NULL
- options:0 = 阻塞等待;WNOHANG = 非阻塞等待
- 返回值:成功返回终止的子进程 PID;失败返回 - 1;非阻塞模式下无已终止子进程返回 0。
七、僵尸进程核心处理
- 产生条件:子进程终止,父进程存活且未回收子进程资源。
- 规避方案:
- 父进程调用 wait ()/waitpid () 等待子进程终止,回收资源(最常用)。
- 父进程提前退出,使子进程成为孤儿进程,由 1 号进程回收资源。
- 通过信号机制,子进程终止时触发信号,父进程在信号处理函数中回收资源。
更多推荐



所有评论(0)