乙個關於自旋鎖 spin lock 問題的討論

2021-07-09 13:31:01 字數 1329 閱讀 3304

前陣子有網友發短訊息問:「...在研究自旋鎖的時候,發現在 spin_lock_irq函式,也就是在自旋鎖中關閉中的這類函式中,既然已經關閉了本地中斷,再禁止搶占有沒有多餘。也就是說,既然本地中斷已經禁止了,在本處理器上是無法被打斷的,本地排程器也無法執行,也就不可以被本地排程程式排程出去..."

從spinlock設計原理看,使用它的時候,在臨界區間是務必確保不會發生程序切換。現在的問題是,如果已經關閉了中斷,在同一處理器上如果不關掉核心搶占的特性,會不會有程序排程的情況發生,如果沒有,那我個人的理解是,在local_irq_disable之後再使用peempt_disable就多此一舉了。

這個在smp系統上最好理解了,假設有a和b兩個處理器,使用spin lock的程序(簡稱"焦點程序"好了)執行在處理器a上,一種很明顯的情形就是如果有個程序(簡稱「睡眠程序」好了)先於焦點執行,但是因為等待網絡卡的乙個資料報,它進入了sleep狀態,然後焦點開始被排程執行,後者在spin lock獲得鎖後進入臨界區,此時網絡卡收到了"睡眠程序「的資料報,因為焦點只是關閉了a上的中斷,所以b還是會接收並處理該中斷,然後喚醒「睡眠程序「,後者進入執行佇列,此時出現乙個排程點,如果」睡眠「的優先順序高於」焦點「,那麼就有程序切換發生了,但是如果焦點所使用的spin lock中關閉了核心搶占,那麼就使得先前的程序切換成為不可能。

如果是在單處理器系統上,local_irq_disable實際上關閉了所有(其實就乙個)處理器的中斷,所有有中斷引起的排程點都不可能存在,此時有無其他與中斷無關的排程點出現呢?在2.4上,因為沒有搶占,這種情形絕無可能,事實上,早期的核心很大程度上是依賴local_irq_disable來做資源保護,這個看看2.4的核心原始碼就很清楚了,裡面有大量的對local_irq_disable函式的直接呼叫。2.6有了搶占的概念,up下關閉中斷,如前所述,實際上已經杜絕了內部因素導致的「就緒佇列中加入乙個程序」這個排程點的可能(內部因素實際上只剩下了乙個處理器的異常,但是關中斷的情形下,即便有異常也不會導致程序的切換),因此到這裡我們可以這樣說,在up上關閉中斷情形下,preempt_disable其實是多餘的。但是我們知道,spin lock是一種核心api,不只是kernel的開發者在用,更多的核心模組(.ko,實際當中更多地表現形式是裝置驅動程式)開發者也在使用。核心的設計者總是試圖將其不能控的**(所謂的外部因素了)可能給核心帶來的損失降低至最小的程度,這個表現在核心對中斷處理框架的設計時尤其明顯,所以在up系統下先後使用local_disable_irq和preempt_disable,只是盡量讓你我可能在spin lock/unlock的臨界區中某些混了頭的**不至於給系統帶來災難,因為難保某些人不會在spin lock的臨界區中,比如去wake_up_interruptible()乙個程序,而被喚醒的程序在可搶占的系統裡就是乙個開啟的潘多拉盒子。0

自旋鎖 spinlock 理解

自旋鎖spinlock是一種對臨界資源進行互斥手訪問的典型手段,其名稱源於他的工作方式。為了獲得乙個自旋鎖,在某cpu上執行的 需先執行乙個原子操作,該操作測試並設定test and set某個記憶體變數,由於他是原子操作,所以在該操作完成之前其它執行單元不可能訪問這個記憶體變數。如果測試結果表明鎖...

執行緒同步 自旋鎖 SpinLock

自旋鎖 spinlock 是指當乙個執行緒在獲取鎖的時候,如果鎖已經被其它執行緒獲取,那麼該執行緒將迴圈等待,然後不斷的判斷鎖是否能夠被成功獲取,直到獲取到鎖才會退出迴圈。什麼情況下使用自旋鎖 自旋鎖非常有助於避免阻塞,但是如果預期有大量阻塞,由於旋轉過多,您可能不應該使用自旋鎖。當鎖是細粒度的並且...

自旋鎖spinlock剖析與改進

自旋鎖spinlock剖析與改進 原文 1,spinlock介紹 spinlock又稱自旋鎖,執行緒通過busy wait loop的方式來獲取鎖,任時刻只有乙個執行緒能夠獲得鎖,其他執行緒忙等待直到獲得鎖。spinlock在多處理器多執行緒環境的場景中有很廣泛的使用,一般要求使用spinlock的...