知识全景图/ 软件工程与系统/ 如何设计系统/ 如何设计操作系统/ 进程与调度器

如何设计进程与调度器

把“正在跑的程序”设计成可暂停、可恢复、可限制、可清理的内核对象。

定位:这页不解释“进程是什么”的教材定义。它只从一个失败出发:用户程序可能不归还 CPU。为了解决这个失败,内核必须发明进程、上下文、状态机、定时器中断和调度器。
一、坏场景:用户程序不归还 CPU
失败:内核跳到用户程序后,程序执行死循环。CPU 没有“公平意识”,它会一直执行下一条指令。没有中断和调度,内核拿不回控制权。
为什么失败被迫设计设计目标
CPU 不会主动切回内核定时器中断周期性打断当前程序
打断后要知道“当前是谁”进程对象保存程序身份、状态和资源
切走后要能回来上下文保存保存寄存器、PC、SP 等执行现场
多个程序等待运行调度器决定下一个运行谁
二、进程的最小结构
字段保存什么如果没有会怎样
pid进程身份无法 kill、wait、调试或记录归属
staterunning、ready、blocked、zombie调度器不知道它该运行还是等待
context寄存器、PC、SP、flags切走后无法从原位置继续
address_space该进程的地址空间引用无法隔离内存
open_filesfd 到内核文件对象的映射read / write 不知道操作哪个资源
limitsCPU、内存、fd、子进程上限一个程序可以耗尽系统
三、状态机比名词更重要
状态变化触发原因内核动作
new → ready进程创建完成放入 ready 队列
ready → running调度器选中恢复上下文,切到该进程
running → ready时间片用完保存上下文,重新排队
running → blocked等待 IO、sleep、wait从运行队列移走,记录等待条件
blocked → readyIO 完成或条件满足唤醒进程
running → zombie进程退出保留退出码,等待父进程回收
四、第一版调度器只做轮转
先不要复杂:第一版不要急着做多级反馈队列、实时调度或 CFS。先证明“坏程序不能饿死别人”。
问题第一版选择代价
谁先运行ready 队列 FIFO简单公平,不懂任务差异
运行多久固定时间片易实现,但交互响应不一定最优
等待 IO 怎么办blocked,完成后唤醒需要可靠的等待条件和唤醒路径
进程退出怎么办zombie,父进程 wait 后清理父进程不回收会产生僵尸
on_timer_interrupt: save current.context if current.state == running: current.state = ready run_queue.push(current) next = run_queue.pop() next.state = running restore next.context
五、验收实验
实验通过标准证明了什么
死循环实验死循环进程存在时,打印进程仍周期性输出抢占调度成立
阻塞实验等待输入的进程不占 CPU,输入到达后恢复blocked / wakeup 成立
退出实验子进程退出后,父进程 wait 得到退出码生命周期和清理成立
限额实验进程创建超过上限时返回错误进程表不是无限资源
六、回到操作系统主线
下一页:虚拟内存与地址空间
进程能轮流运行后,下一个灾难是程序乱写内存。继续看 如何设计虚拟内存与地址空间
回总页
如果你想看完整 ToyOS 设计路线,回到 如何设计操作系统
一句话:进程不是“程序的另一个名字”,而是内核为了夺回 CPU、保存现场、限制资源、清理失败而设计出来的账本对象。