6.7 睡眠锁

有时xv6需要长时间保持锁。例如,文件系统(第8章)在磁盘上读写文件内容时保持文件锁定,这些磁盘操作可能需要几十毫秒。如果另一个进程想要获取自旋锁,那么长时间保持自旋锁会导致获取进程在自旋时浪费很长时间的CPU。自旋锁的另一个缺点是,一个进程在持有自旋锁的同时不能让出(yield)CPU,然而我们希望持有锁的进程等待磁盘I/O的时候其他进程可以使用CPU。持有自旋锁时让步是非法的,因为如果第二个线程试图获取自旋锁,就可能导致死锁:因为acquire不会让出CPU,第二个线程的自旋可能会阻止第一个线程运行并释放锁。在持有锁时让步也违反了在持有自旋锁时中断必须关闭的要求。因此,我们想要一种锁,它在等待获取锁时让出CPU,并允许在持有锁时让步(以及中断)。

Xv6以睡眠锁(sleep-locks)的形式提供了这种锁。acquiresleep (kernel/sleeplock.c:22) 在等待时让步CPU,使用的技术将在第7章中解释。在更高层次上,睡眠锁有一个被自旋锁保护的锁定字段,acquiresleepsleep的调用原子地让出CPU并释放自旋锁。结果是其他线程可以在acquiresleep等待时执行。

因为睡眠锁保持中断使能,所以它们不能用在中断处理程序中。因为acquiresleep可能会让出CPU,所以睡眠锁不能在自旋锁临界区域中使用(尽管自旋锁可以在睡眠锁临界区域中使用)。

因为等待会浪费CPU时间,所以自旋锁最适合短的临界区域;睡眠锁对于冗长的操作效果很好。