把“正在跑的程序”设计成可暂停、可恢复、可限制、可清理的内核对象。
| 为什么失败 | 被迫设计 | 设计目标 |
|---|---|---|
| CPU 不会主动切回内核 | 定时器中断 | 周期性打断当前程序 |
| 打断后要知道“当前是谁” | 进程对象 | 保存程序身份、状态和资源 |
| 切走后要能回来 | 上下文保存 | 保存寄存器、PC、SP 等执行现场 |
| 多个程序等待运行 | 调度器 | 决定下一个运行谁 |
| 字段 | 保存什么 | 如果没有会怎样 |
|---|---|---|
pid | 进程身份 | 无法 kill、wait、调试或记录归属 |
state | running、ready、blocked、zombie | 调度器不知道它该运行还是等待 |
context | 寄存器、PC、SP、flags | 切走后无法从原位置继续 |
address_space | 该进程的地址空间引用 | 无法隔离内存 |
open_files | fd 到内核文件对象的映射 | read / write 不知道操作哪个资源 |
limits | CPU、内存、fd、子进程上限 | 一个程序可以耗尽系统 |
| 状态变化 | 触发原因 | 内核动作 |
|---|---|---|
| new → ready | 进程创建完成 | 放入 ready 队列 |
| ready → running | 调度器选中 | 恢复上下文,切到该进程 |
| running → ready | 时间片用完 | 保存上下文,重新排队 |
| running → blocked | 等待 IO、sleep、wait | 从运行队列移走,记录等待条件 |
| blocked → ready | IO 完成或条件满足 | 唤醒进程 |
| running → zombie | 进程退出 | 保留退出码,等待父进程回收 |
| 问题 | 第一版选择 | 代价 |
|---|---|---|
| 谁先运行 | ready 队列 FIFO | 简单公平,不懂任务差异 |
| 运行多久 | 固定时间片 | 易实现,但交互响应不一定最优 |
| 等待 IO 怎么办 | blocked,完成后唤醒 | 需要可靠的等待条件和唤醒路径 |
| 进程退出怎么办 | zombie,父进程 wait 后清理 | 父进程不回收会产生僵尸 |
| 实验 | 通过标准 | 证明了什么 |
|---|---|---|
| 死循环实验 | 死循环进程存在时,打印进程仍周期性输出 | 抢占调度成立 |
| 阻塞实验 | 等待输入的进程不占 CPU,输入到达后恢复 | blocked / wakeup 成立 |
| 退出实验 | 子进程退出后,父进程 wait 得到退出码 | 生命周期和清理成立 |
| 限额实验 | 进程创建超过上限时返回错误 | 进程表不是无限资源 |