同步機制比較:Spinlock v.s. Mutex

Spinlock 與 Mutex 都是很常用的同步機制,今天來看看這兩者在 Windows 上有什麼樣的不同!(推薦 MSDN 上的 Locks, Deadlocks, and Synchronization,寫得很不錯!)

Spinlock

我們可以簡單的從中文翻譯「自旋鎖」看出一點端倪,基本上就是個 Busy waiting 的動作,得一直等待指定的鎖被釋放之後,才可以繼續進行下一步動作。概念上非常簡單,實作上就不是如此了。例如:如果鎖還沒被釋放這個執行緒就被 swap-out 而進入 sleep 狀態怎麼辦?兩個執行緒同時要求取鎖的同步該怎麼處理?

Mutex

事實上 Mutex 是一種抽象概念:透過一個變數或物件確保 Critical Section 內的資料同一時間內只會有單一存取。所以文章標題本身就不是個很精確的命題。根據 MSDN 上的說明,Mutex 約可分為以下三類同步機制:

  • (Interrupt/Queued) Spinlock
  • (Fast/Kernel/Unsafe Fase) Mutex
  • Synchronization Event

了解後,我們知道我們真正該比較的是 KeAcquireSpinLock 與 KeWaitForMutexObject

那麼,究竟有什麼不同?

簡單的介紹之後,我們可以發現一個重點就是:CPU 使用率。對於 Spinlock 來說,是佔用 CPU 時間來做等待動作的,也因此,我們可以歸納出兩者的不同的使用時機:

  • 同質多核心的環境下,Critical Section 所花費的時間如果不多,適合 Spinlock,因為我們可以減少 Context Switch 的時間。(單核心其實兩者的比較沒有太多意義,因為某些系統會透過中段的開關實作 Spinlock)
  • 在 Windows 中,使用 Spinlock 會把該執行緒提升到 DISPATCH_LEVEL,這在某些情況下可能是不允許的,因此這時候就不得不使用 Mutex 了(APC_LEVEL)。
  • Mutex 比較適合保護一塊區域(所需時間長),而 Spinlock 比較適合保護一個變數(所需時間短)。

Semaphore?

說到同步怎麼可以不提 Semaphore?最容易搞混的就是 Mutex 與 Semaphore 了,因為 Mutex 有時候也被拿來當做同步機制的概稱。其實 Mutex = Binary Semaphore,如果我們只說 Semaphore 通常都是指 Counted Semaphore = Reentrant Mutex。 除此之外,在某些系統中(e.g., Windows),還有些細部差別 。

  1. Semaphore 可以設定同時被 Acquire 的次數,而 Mutex 則無法。所以若 Critical Section 允許被兩個以上的執行緒執行的話,通常我們會採用 Semaphore(但相對帶來的副作用用就是 Deadlock)。
  2. Mutex 只能被當初 Acquire 的執行緒 Release,Semaphore 則無此限制。

想要更深入瞭解的話,可以參考這篇文章