1. 程式人生 > >spin_lock、spin_lock_irq、spin_lock_irqsave區別

spin_lock、spin_lock_irq、spin_lock_irqsave區別

void spin_lock(spinlock_t *lock);

void spin_lock_irq(spinlock_t *lock);

void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);


1、spin_lock與spin_lock_irq區別

在Linux核心中何時使用spin_lock,何時使用spin_lock_irqsave很容易混淆。首先看一下程式碼是如何實現的。

spin_lock的呼叫關係

     spin_lock

            |

           + ----->  raw_spin_lock

|

+------>  _raw_spin_lock

                         |

                        +--------> __raw_spin_lock

[cpp] view plain copy
  1. static inline void __raw_spin_lock(raw_spinlock_t *lock)  
  2. {  
  3.         preempt_disable();  
  4.         spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);  
  5.         LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);  
  6. }  

spin_lock_irq的呼叫關係

    spin_lock_irq

                |

               +-------> raw_spin_lock_irq

                                           |

                                          +---------> _raw_spin_lock_irq

                                                                      |

                                                                      +------------> __raw_spin_lock_irq

[cpp] view plain copy
  1. static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)  
  2. {  
  3.         local_irq_disable();  
  4.         preempt_disable();  
  5.         spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);  
  6.         LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);  
  7. }  

可以看出來他們兩者只有一個差別:是否呼叫local_irq_disable()函式, 即是否禁止本地中斷。

在任何情況下使用spin_lock_irq都是安全的。因為它既禁止本地中斷,又禁止核心搶佔。

spin_lock比spin_lock_irq速度快,但是它並不是任何情況下都是安全的。

舉個例子:程序A中呼叫了spin_lock(&lock)然後進入臨界區,此時來了一箇中斷(interrupt),

該中斷也執行在和程序A相同的CPU上,並且在該中斷處理程式中恰巧也會spin_lock(&lock)

試圖獲取同一個鎖。由於是在同一個CPU上被中斷,程序A會被設定為TASK_INTERRUPT狀態,

中斷處理程式無法獲得鎖,會不停的忙等,由於程序A被設定為中斷狀態,schedule()程序排程就

無法再排程程序A執行,這樣就導致了死鎖!

但是如果該中斷處理程式執行在不同的CPU上就不會觸發死鎖。 因為在不同的CPU上出現中斷不會導致

程序A的狀態被設為TASK_INTERRUPT,只是換出。當中斷處理程式忙等被換出後,程序A還是有機會

獲得CPU,執行並退出臨界區。

所以在使用spin_lock時要明確知道該鎖不會在中斷處理程式中使用。

2、spin_lock_irq與spin_lock_irqsave區別

spin_lock_irqsave在進入臨界區前,儲存當前中斷暫存器flag狀態,關中斷,進入臨界區,在退出臨界區時,把儲存的中斷狀態寫回到中斷暫存器。

spin_lock_irq在進入臨界區前不儲存中斷狀態,關中斷,進入臨界區,在退出臨界區時,開中斷。


spin_lock_irqsave鎖返回時,中斷狀態不會被改變,呼叫spin_lock_irqsave前是開中斷返回就開中斷。

spin_lock_irq鎖返回時,永遠都是開中斷,即使spin_lock_irq前是關中斷

轉自:http://blog.csdn.net/zhanglei4214/article/details/6837697

http://blog.csdn.net/lbo4031/article/details/8894830