Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

上下文切换

复习

  • 程序如何变成进程:区分静态的程序文件和运行中的进程
  • 进程的创建与结束:父子进程、退出状态和资源回收
  • 进程控制块与进程状态:内核在哪里记录进程,以及三种状态的含义

TL;DR

  • 上下文就是一个进程当前的运行现场:PC、寄存器、栈等
  • 上下文切换:保存当前进程的现场,恢复下一个进程的现场
  • 切换由内核完成,是实现“同时运行多个程序”的关键
  • 切换本身不干“有用功”,还伴随额外开销,因此不宜过于频繁

正文

  就绪队列里排着好几个进程,可 CPU 只有一个。让谁上?跑一会儿之后,又该怎么换人?

  换人这件事的关键,在于记住上一个人做到哪了

上下文是什么

  一个进程正在运行时,它的全部“现场”都体现在 CPU 的状态里:

  • PC 指向哪条指令
  • 各个寄存器里是什么值
  • 栈指针指向哪里
  • 它正在用哪片内存

  这些信息合起来,就叫进程的上下文(context)。只要把上下文原样恢复,进程就能像从没被打断过一样继续跑。

切换的三步

  上下文切换(context switch)大致分三步:

  1. 保存:把当前进程的 PC、寄存器等,存进它的 PCB
  2. 选择:内核从就绪队列里挑出下一个要运行的进程
  3. 恢复:从那个进程的 PCB 里,把它的现场装回 CPU

  做完这三步,CPU 上跑的就已经是另一个进程了。

进程 A 运行
  │ 保存 A 的上下文到 A 的 PCB
  │ 从就绪队列选中 B
  │ 从 B 的 PCB 恢复 B 的上下文
  ▼
进程 B 运行

  好比两个人接力做同一道题:第一个人做一半要走,先把“算到哪一步、草稿写了什么”记下来;第二个人接手时,照着记下的内容接着算。题没变,只是换了个脑子。

切换的开销

  上下文切换让“多个程序同时运行”成为可能,但它并不便宜:

  • 保存和恢复现场本身就要花时间,这段工夫不推进任何进程
  • 切换会打乱 CPU 内部为当前进程做的优化,比如缓存和流水线

  所以,切换太频繁会拖慢整体效率。好的调度,既要让大家都有机会跑,又要尽量减少无谓的切换。

什么时候切换

  切换不会无缘无故发生,通常由这几件事引起:

  • 时间片用完:一个进程跑了足够久,该让位了
  • 主动阻塞:进程要等 I/O,主动让出 CPU
  • 被更高优先级的进程打断:来了更要紧的事

  到这里,进程“轮流上 CPU”的机制就通了。可到底该让谁先上、上多久?这属于操作系统的另一个核心话题——调度。下一章,我们先看看调度要解决哪些矛盾。

思考题

  如果上下文切换不需要保存和恢复现场,直接让两个进程“混着跑”,会出什么问题?为什么“保存现场”是不可省略的一步?

小结

知识点

  • 上下文是进程的运行现场:PC、寄存器、栈等
  • 上下文切换:保存当前、选择下一个、恢复下一个
  • 切换是分时多任务的基础,但有开销
  • 切换常由时间片耗尽、阻塞或更高优先级打断引起

参考资料

  1. Wikipedia(zh):上下文切换:context switch
  2. Wikipedia(zh):进程控制块:现场的保存位置

思考题答案(仅供参考)

  如果两个进程“混着跑”,它们会共用同一组寄存器和 PC:A 刚把一个中间结果放进寄存器,B 立刻把它覆盖掉;PC 也会在两条指令流之间乱跳。结果就是两边都算错。保存现场的意义,正是把每个进程的“进度”完整地存起来,互不覆盖;恢复现场,则是让它接着自己的进度继续。少了这一步,就没法把一个 CPU 安全地分给多个进程。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪