自旋鎖是什麼?

本文內容如有錯誤、不足之處,歡迎技術愛好者們一同探討,在本文下面討論區留言,感謝。

定義

自旋鎖 spin lock

下面內容摘自維基百科

在這裏插入圖片描述

在軟件工程中,自旋鎖是一種鎖,它使試圖獲取它的線程在循環(“自旋”)中簡單地等待,同時反覆檢查該鎖是否可用。由於線程保持運行狀態,但未執行有用的任務,因此使用這種鎖是一種繁忙的等待。一旦獲得了自旋鎖,通常將一直保持這種狀態,直到顯式釋放它們爲止,儘管在某些實現中,如果正在等待線程(持有鎖的線程)阻塞或“進入睡眠狀態”,則它們可能會自動釋放。

因爲自旋鎖避免了操作系統進程上下文切換帶來的CPU消耗,所以如果線程可能僅在短時間內被阻塞,則自旋鎖非常有效。因此,操作系統內核經常使用自旋鎖。但是,自旋鎖如果保持更長的時間會變得很浪費,因爲它們可能會阻止其他線程運行。線程持有鎖的時間越長,則持有該鎖的線程將被OS調度程序中斷的風險越大。如果發生這種情況,則其他線程將保持“旋轉”狀態(反覆嘗試獲取該鎖),而持有該鎖的線程在釋放它方面並未取得進展。結果是無限期推遲,直到持有鎖的線程可以完成並釋放它爲止。在單處理器系統上尤其如此,在該系統上,每個具有相同優先級的等待線程都可能浪費其量子時間(線程可以運行的分配時間)旋轉,直到持有鎖的線程最終完成。

特點

根據上面的描述可以總結自旋鎖以下幾個特點:

  • 在循環中,線程反覆簡單地等待(“旋轉”)檢查,直到鎖可用爲止。
  • 自旋鎖(spin lock)是一種繁忙的等待,因爲線程通過執行無用的任務(例如空for循環),而保持活動狀態。
  • 當自旋鎖在只自旋很短的時間時,效率非常高。
  • 如果自旋時間較長,可能會造成浪費。

和互斥鎖比較

互斥鎖的問題是使線程進入睡眠狀態並再次喚醒它們都是相當耗時的操作,並且需要執行大量的CPU指令。如果現在互斥鎖僅鎖定很短的時間,則使線程進入睡眠狀態並再次喚醒它所花費的時間可能會超過該線程實際睡眠的時間,甚至可能超過該線程將要執行睡眠的時間。不斷輪詢自旋鎖浪費了CPU的時間,如果自旋鎖保持更長的時間,則浪費更多的CPU時間,而如果線程處於睡眠狀態會更好。

適用場景

在單核/單CPU系統上使用自旋鎖是沒有意義的,因爲只要自旋鎖輪詢阻止了唯一可用的CPU內核,其他線程就無法運行,並且由於沒有其他線程可以運行,因此鎖不會被解鎖。自旋鎖只會浪費那些系統上的CPU時間,沒有真正的好處。如果改爲讓該線程進入睡眠狀態,則另一個線程可能會立即運行,可能會解除鎖定,然後在第一個線程再次喚醒後允許其繼續處理。

在多核/多CPU系統上,只有大量鎖定僅在很短的時間內保持不變,浪費時間不斷使線程進入睡眠狀態並再次喚醒它們可能會顯着降低運行時性能。當使用自旋鎖時,線程有機會利用其完整的運行時長(始終僅在很短的時間段內阻塞,然後立即繼續其工作),從而提高了處理吞吐量。

結論

由於開發人員是無法預先知道互斥或自旋鎖是否會更好(例如,因爲目標體系結構的CPU內核數量未知),因此操作系統也無法知道某個代碼段是否已針對單核或Windows優化。在多核環境中,大多數系統並不嚴格區分互斥鎖和自旋鎖。實際上,大多數現代操作系統都具有混合互斥鎖和混合自旋鎖。

混合是什麼意思?

混合互斥鎖首先在多核系統上的行爲就像自旋鎖。如果線程無法鎖定互斥鎖,則不會立即進入休眠(sleep)狀態,因爲互斥鎖可能很快就會被解鎖,因此互斥鎖將首先表現得像自旋鎖。只有在一定時間(或重試或任何其他測量因素)之後仍未獲得鎖定時,線程才真正進入睡眠狀態。如果相同的代碼在只有一個內核的系統上運行,則互斥鎖將不會自旋鎖。

混合自旋鎖起初的行爲類似於普通自旋鎖,但爲避免浪費過多的CPU時間,它可能有一個後置(back-off) 策略(strategy)。它通常不會使線程立即進入睡眠狀態(因爲使用自旋鎖時不會發生這種立即進入睡眠狀態情況),但是它在一定情況下(在一定時間後停止)將會停止線程,允許另一個線程運行,因此增加了自旋鎖被解鎖(unlock)的機會(純線程切換通常比涉及使線程進入休眠狀態並稍後喚醒它更節省效率(waking it up))。

結尾

自旋鎖不但出現在操作系統中,在編程中也經常出現,比如Atomic類中的自旋判斷。實現方式如下

AtomicInteger.java

public final int getAndUpdate(IntUnaryOperator updateFunction) {
     int prev, next;
     do {
         prev = get();
         next = updateFunction.applyAsInt(prev);
     } while (!compareAndSet(prev, next));
     return prev;
 }

代碼中的do-while語句塊就是自旋鎖的示例。

參考資料

When should one use a spinlock instead of mutex?(什麼時候應該使用自旋鎖而不是互斥鎖?

What is a spin lock? (什麼是自旋鎖

What is spin lock?(什麼是自旋鎖

Spinlock(自旋鎖

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