进程管理实战:fork实现与IPC通信全流程 - 第1节
1.1 进程的定义
进程(Process)是操作系统对一个正在运行的程序的一种抽象,是系统进行资源分配和调度的基本单位。从内核视角看,进程是程序在某个数据集合上的一次执行活动,是动态的、有生命周期的实体。
核心定义:进程是操作系统为正在执行的程序提供的运行环境,包括代码、数据、堆栈、寄存器状态以及系统资源(如打开的文件、信号处理函数等)的集合。
1.2 进程与程序的区别
程序(Program)是静态的指令集合,存储在磁盘上;进程是动态的执行实例,存在于内存中。两者在多个维度存在本质差异:
| 对比维度 | 程序 | 进程 |
|---|---|---|
| 存在形式 | 静态文件(如 ELF 格式的可执行文件) | 动态实体,由内核管理 |
| 生命周期 | 永久存在(除非被删除) | 从创建到终止,有明确的生灭过程 |
| 资源占用 | 仅占用磁盘空间 | 占用内存、CPU、文件描述符等系统资源 |
| 并发性 | 不具备并发执行能力 | 多个进程可并发执行 |
| 对应关系 | 一个程序可对应多个进程 | 一个进程只能对应一个程序 |
| 数据结构 | 无内核数据结构 | 拥有进程控制块(PCB) |
记忆口诀:程序是菜谱(静态),进程是炒菜过程(动态)。同一个菜谱可以同时被多个厨师执行,对应一个程序可以产生多个进程。
1.3 进程的组成
一个进程在内存中由三大部分组成:进程控制块(PCB)、代码段和数据段。这三者共同构成了进程的完整映像。
1.3.1 进程控制块(PCB)
PCB 是操作系统为每个进程维护的核心数据结构,是进程存在的唯一标识。Linux 中 PCB 由 task_struct 结构体实现,包含以下关键信息:
- 进程标识符(PID):唯一标识一个进程的数字
- 进程状态:运行、就绪、阻塞、终止等
- 程序计数器:下一条要执行的指令地址
- CPU 寄存器:保存进程切换时的上下文
- 内存管理信息:页表、地址空间等
- 文件描述符表:进程打开的文件列表
- 调度信息:优先级、时间片等
- 父子进程关系:指向父进程和子进程的指针
1.3.2 代码段(Text Segment)
代码段存放程序的机器指令,通常是只读的,防止程序在运行时意外修改自身指令。多个进程如果运行同一个程序(如多个 bash 进程),可以共享同一份代码段,节省内存。
1.3.3 数据段(Data Segment)
数据段包含程序运行所需的变量数据,进一步细分为:
- 初始化数据段:存放已初始化的全局变量和静态变量
- 未初始化数据段(BSS):存放未初始化的全局变量和静态变量,程序加载时自动清零
- 堆(Heap):动态分配的内存区域,如
malloc()分配的空间 - 栈(Stack):存放局部变量、函数参数、返回地址等
常见误区:初学者常把"进程"和"程序"混为一谈。在 Linux 中,使用
ps 命令看到的是进程列表,而使用 file 命令查看的是程序文件。一个程序可以启动多个进程(如同时打开多个终端),每个进程拥有独立的 PCB 和数据段。
1.4 进程内存布局示意图
下图展示了进程在内存中的典型布局,清晰呈现代码段、数据段、堆、栈的分布关系:
1.5 PCB 与进程关系示意图
下图展示了 PCB 在进程管理中的核心地位,以及内核如何通过 PCB 链表管理所有进程:
1.6 进程状态与生命周期
进程在运行过程中会经历多种状态转换,Linux 中常见的进程状态包括:
- 运行态(Running):进程正在 CPU 上执行
- 就绪态(Ready):进程已具备运行条件,等待 CPU 调度
- 阻塞态(Blocked):进程等待某个事件(如 I/O 完成)
- 僵尸态(Zombie):进程已终止,但 PCB 尚未被父进程回收
- 暂停态(Stopped):进程收到 SIGSTOP 等信号暂停执行
实战要点:在 Linux 中,使用
ps -aux 可以查看所有进程的状态。STAT 列中 R 表示运行,S 表示睡眠(阻塞),Z 表示僵尸,T 表示暂停。僵尸进程是初学者常遇到的问题,需要父进程调用 wait() 或 waitpid() 来回收。
1.7 本章小结
| 知识点 | 核心要点 |
|---|---|
| 进程定义 | 程序的一次动态执行,资源分配和调度的基本单位 |
| 进程 vs 程序 | 动态 vs 静态;有生命周期 vs 永久存在;占用资源 vs 仅占磁盘 |
| PCB | 进程控制块,内核管理进程的核心数据结构,Linux 中为 task_struct |
| 代码段 | 只读指令区,多个进程可共享同一程序代码 |
| 数据段 | 包含全局变量、静态变量、堆、栈,每个进程独立 |
| 进程状态 | 运行、就绪、阻塞、僵尸、暂停,通过状态转换实现调度 |