1.概述
它是为实现保护共享资源而提出一种锁机制。自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
2.优缺点
这是一种比较低级的保护数据结构或者代码片段的方法,优点是快速简单,效率高,一般应用于比较短时间的资源占用。但可能存在两个缺点:
1)死锁。试图递归调用自旋锁必然引起死锁。因此,递归程序绝不能在持有自旋锁的时候调用它自己,也不能在递归调用时试图获得相同的自旋锁。
2)过多占用CPU资源。自旋锁在锁定的时候,申请者不会睡眠,会一直在循环等待,会持续尝试。因此,单cpu的自旋锁会让其他process动不了。为此,一般自旋锁实现会有一个参数限定最多持续尝试次数. 超出后, 自旋锁放弃当前time slice. 等下一次机会。
如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作,
3.实现
1)在单处理机环境中
可以使用硬件提供的swap指令或test_and_set指令实现进程互斥,(Swap指令:交换两个内存单元的内容;test_and_set指令取出内存某一单元(位)的值,然后再给该单元(位)赋一个新值,关于为何这两条指令能实现互斥我们不在赘述,读者可以了解其算法) 这些指令涉及对同一存储单元的两次或两次以上操作,这些操作将在几个指令周期内完成,但由于中断只能发生在两条机器指令之间,而同一指令内的多个指令周期不可中断,从而保证swap指令或test_and_set指令的执行不会交叉进行。
2)为在多CPU环境中利用test_and_set指令实现进程互斥,硬件需要提供进一步的支持,以保证test_and_set指令执行的原子性. 这种支持目前多以“锁总线”(bus locking)的形式提供的,由于test_and_set指令对内存的两次操作都需要经过总线,在执行test_and_set指令之前锁住总线,在执行test_and_set指令后开放总线,即可保证test_and_set指令执行的原子性,用法如下:
//多处理机互斥算法(自旋锁算法)
do{
b=1;
while(b){
lock(bus);
b = test_and_set(&lock);
unlock(bus);
}
//临界区
lock = 0;
//其余部分
}while(1)
4.总结
自旋锁实际上是用忙等的方式等待时间。
5.参考资料