自旋锁(网络博客等学习和整理)

时间:2014.06.17

地点:基地

-----------------------------------------------------------------------------------

一、简述

   自旋锁(spinlock)是为防止多处理器并发而引入的一种锁,在内核中大量应用于中断处理。

-----------------------------------------------------------------------------------

二、自旋锁的概念

   和互斥锁类似,也是为实现保护共享资源而提出的一种锁机制,都是为了解决对某项资源的互斥使用。无论是互斥锁也好还是自旋锁也好,在任何时刻,最多只能有一个保存者,即任何时刻顶多只能有一个执行单元可以获得锁

-----------------------------------------------------------------------------------

三、自旋锁与互斥锁的区别

  互斥锁和自旋锁的区别主要在于调度机制的区别:对于互斥锁,如果资源已经被占用,资源申请只能进入睡眠状态,但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保存,调用者就一直循环在那里看是否该自旋锁的保存着已经释放了锁,自选一词由此得名,打不开锁,就一直在那自我旋转试图直到打开。

-----------------------------------------------------------------------------------

四、自旋锁原理和应用场合

    和互斥锁一样,一个执行单元如果想要访问被自旋锁保护的共享资源,必须先得到所,在访问完共享资源后,必须释放锁。若在获得自旋锁时,没有任何执行单元保持该锁,那么就立刻得到该锁,反之,若果在获取自旋锁时该锁已经有保持着了,那么获得该锁操作将自旋在那里,直到自旋锁的保持着释放了锁。

4.1自旋锁存在的问题

      试图递归地获得自旋锁必然会引起死锁,在递归程序的持有实例在第二个实例循环,以试图获得相同的自旋锁时,但此时自旋锁又未被释放,在递归程序中使用自旋锁应遵守以下策略:递归程序绝不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁,此外如果一个进程已经将资源锁定,那么,即使其它申请这个资源的进程不停地疯狂自旋也无法获得资源,从而进入死循环。因此,如果不加限制,由于新的额资源申请者一直在循环等待,因此自旋锁在锁定时如果不成功它不会睡眠,而是持续尝试,这样,特别是在单CPU时,自旋锁的这种持续旋转会让其他进程动不了,因此,一般在实现自旋锁时,会有一个参数限定最多持续尝试的次数,超出次数后,自旋锁放弃当前的时间片等待下一次机会

4.2应用场景

        由上可知,自旋锁比较适用于锁的使用者保持锁时间比较短的情况。也正是由于自旋锁的使用者一般保持锁时间非常短,因此选择自旋而不是睡眠非常必要,自旋锁的效率也远高于互斥锁。信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但若被保护的共资源需要再中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。

4.3细节

          在单处理机环境中可以使用硬件提供的swap指令或test_and_set指令实现进程互斥(swap指令用于交换两个内存单元的内容,test_and_set指令用于取出内存某一单元位的值,然后再给该单元(位)赋一次新值,这些指令涉及对同一存储单元的两次或两次以上的操作,这些操作将在几个指令周期内完成,但由于中断只能发生在两条机器指令之间,而同一指令内的多个指令周期不可中断,从而保证swap指令或test_and_set指令的执行不会交叉进行。但在多处理机环境中情况有所不同,例如test_and_set指令包括“取”、“送”两个指令周期,两个CPU执行test_and_set(lock)可能发生指令周期上的交叉,假如lock初始为0, CPU1和CPU2可能分别执行完前一个指令周期并通过检测(均为0),然后分别执行后一个指令周期将lock设置为1,结果都取回0作为判断临界区空闲的依据,从而不能实现互斥。


  为在多CPU环境中利用test_and_set指令实现进程互斥,硬件需要提供进一步的支持,以保证test_and_set指令执行的原子性. 这种支持目前多以“锁总线”(bus locking)的形式提供的,由于test_and_set指令对内存的两次操作都需要经过总线,在执行test_and_set指令之前锁住总线,在执行test_and_set指令后开放总线,即可保证test_and_set指令执行的原子性。自旋锁是一种对多处理器相当有效的机制,而在单处理器非抢占式的系统中基本上没有作用。自旋锁在SMP系统中应用得相当普遍。在许多SMP系统中,允许多个处理机同时执行目态程序,而一次只允许一个处理机执行操作系统代码,利用一个自旋锁可以很容易实现这种控制.一次只允许一个CPU执行核心代码并发性不够高,若期望核心程序在多CPU之间的并行执行,将核心分为若干相对独立的部分,不同的CPU可以同时进入和执行核心事实上,自旋锁的初衷就是:在短期间内进行轻量级的锁定。一个被争用的自旋锁使得请求它的线程在等待锁重新可用的期间进行自旋(特别浪费处理器时间),所以自旋锁不应该被持有时间过长。如果需要长时间锁定的话, 最好使用信号量。1自旋锁实际上是忙等锁。

  当锁不可用时,CPU一直循环执行“测试并设置”该锁直到可用而取得该锁,CPU在等待自旋锁时不做任何有用的工作,仅仅是等待(自旋锁在自旋时此时CPU是一直空闲的),因此,只有在占用锁的时间极短的情况下,使用自旋锁才是合理的。当临界区很大或有共享设备的时候,需要较长时间占用锁,使用自旋锁会降低系统的性能。自旋锁可能导致系统死锁引发这个问题最常见的情况是递归使用一个自旋锁,即如果一个已经拥有某个自旋锁的CPU 想第二次获得这个自旋锁,则该CPU 将死锁。此外,如果进程获得自旋锁之后再阻塞,也有可能导致死锁的发生。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章