Linux中的自旋锁,标准用法是spin_lock(加锁)、spin_unlock(解锁),可是内核中往往不是这么用的,这是为什么呢?这封GeeP博文说的非常清楚http://www.geeksofpune.in/drupal/?q=node/75

    线程可以分为一般线程和irq线程,Linux使用irq处理中断问题。一般线程没什么可说的,irq线程运行在一个较高的特权模式下,可以抢占CPU。基于这种情况,使用spin_lock会造成死锁。比如:一般线程获得锁,irq线程此时进行抢占,试图上锁。但是锁已经被一般线程获得,irq线程无法获得锁,可是由于irq线程抢占了CPU,一般线程也无法继续执行以释放锁,于是陷入死锁。

      之所以死锁,在于两个方面:1. 线程是可以被抢占的;2. 线程如果不能获得锁,便不继续进行。打破任何一个因素,都不会造成死锁。因此,避免死锁就从这两方面入手,分为两种方法:

    1. 加锁不使用spin_lock,而采用spin_lock_irqsave。后者在x86平台上,可以理解为执行了如下操作:对于当前使用的CPU,保存寄存器状态,关硬件中断,试图获得锁。这种方法由于关闭了irq中断,使得一般线程不能被irq线程抢占,进而避免了死锁发生。但是需要注意,由于加锁要保存寄存器状态,那么解锁的时候也要相应的进行恢复,需要使用spin_unlock_irqrestore解锁。

    2. 加锁不使用spin_lock,而采用spin_trylock,特别是irq线程一定要这么使用。该函数尝试获得锁,如果获得返回成功(非0值),否则返回失败。因此,即使irq线程进行了抢占,由于采用此函数并不会阻塞线程继续执行,irq线程可以正常退出,获得锁的原进程可以继续执行,也避免了死锁。由于不像第一种方法需要在加锁时候进行很多准备工作,使用spin_unlock即可以进行解锁。

      至于具体的使用方法,参见GeeP的博文。