6.0: xv6中的锁机制

注释:该内容基于原版课程的textbook和源代码,在大模型辅助翻译的基础上进行的整理。

大多数内核(包括 xv6)都会交错地执行多个活动。交错的一个来源是多处理器硬件:计算机具有多个独立执行的 CPU,例如 xv6 所使用的 RISC-V。 这些多个 CPU 共享物理 RAM,xv6 利用这种共享来维护所有 CPU 都会读取和写入的数据结构。这种共享带来了可能的数据访问风险,即一个 CPU 在读取数据结构时,另一个 CPU 可能正处于更新该数据结构的过程中, 或者多个 CPU 可能同时更新同一个数据结构;如果设计不当,这种并行访问很可能会导致错误的结果或数据结构损坏。即使在单处理器上,内核也可能在多个线程之间切换 CPU,从而使其交错的执行,从用户的角度看来好像是同时执行一样。 最后,如果设备中断处理程序修改了与可中断代码相同的数据,并且中断在恰好不合时宜的时间发生,也可能会损坏数据。“并发”(cocurrency)一词指的是由于多处理器并行、线程切换或中断而导致的多个线程对应的多条指令流交错执行的情况。

内核中充满了被并发访问的数据。例如,两个 CPU 可以同时调用 kalloc,从而同时从空闲列表的头部取出元素。内核设计者喜欢允许大量并发,因为它可以通过并行性提高性能,并增加响应能力。
然而,作为结果,内核设计者必须在这样的并发条件下确保正确性。实现正确代码的方法有很多种,其中一些比其他的更容易理解。旨在保证并发条件下正确性的策略及其支持的抽象称为并发控制技术。

根据具体情况,xv6 使用了多种并发控制技术;还有许多其他可能的方法。本章重点介绍一种广泛使用的技术:锁。锁提供了互斥,确保每次只有一个 CPU 可以持有锁。
如果程序员为每个共享数据项关联一个锁,并且代码在使用该数据项时始终持有相关的锁,那么该数据项将一次只被一个 CPU 使用。在这种情况下,我们称该锁“保护”了数据项。 虽然锁是一种易于理解的并发控制机制,但它的缺点是可能会限制性能,因为它会将并发操作串行化。

本章其余部分将解释 xv6 为什么需要锁,xv6 如何实现锁,以及如何使用锁。