SMP 系统下的锁互斥
UP系统下的互斥
在单处理器(unique process)系统上,任何允许多个控制路径(多个线程或者多个进程),都会有竞争条件的发生。
1) 短期互斥:在单处理器中,如果系统不允许在内核态抢占,那么就不会出现互斥的问题,只有允许在内核抢占时,也就是分时间片时,才出现互斥的情况。这主要用于修改一个内核共享的数据结构。
实现的方法:禁止抢占
2) 和中断处理程序的互斥:进程和中断处理程序(也就是相当于出现两个控制路径)同时访问共享资源时会发生互斥。
实现的方法:关闭中断
3) 长期互斥:UP系统中,测试标志位并设置,也是通过禁止抢占来实现的。实际上就是短期互斥策略设置加锁标志+进程的睡眠唤醒。
SMP系统下的互斥
对于在SMP情况下,对以1),禁止抢占就不灵了。禁止一个cpu被抢占,并不能禁止其他cpu的抢占。对于2),就出现了关本地中断和关所有cpu中断的情况。
Test-And-Set
经典的并行原语是test-and-set。test-and-set操作自动地从一个内存位置读取一个值然后写入一个新值,并把旧值返回。
test-and-set原语足以实现任何其它并行安全的操作。(实际上,在某些CPU上test-and-set是唯一被提供的此类原语)。 这句话的意思是,SMP系统中只要引入test-and-set操作原语,就可以满足SMP系统下所有的并行操作。下面我们看到SMP的防止竞争的机制spin_lock和semaphore都是基于这个操作原语来完成的。
我们现在一下test-and-set操作原语在x86系统下是如何实现的。
在x86平台上,lock指令正好能够提供这种帮助。(准确地说,lock是一个前缀而非一个单独的指令)lock指令用于在随后的指令执行期间锁住内存总线——至少是对目的内存地址。因为x86可以在内存里直接减值,而无需明确的先把它读入一个寄存器中,这样对于执行一个减值原子操作来说就是万事俱备了:lock内存总线然后立刻对该内存位置执行decl操作。
Spin_lock锁和semaphore都是基于这个基本的原语来实现的。下一次再说。