2010-05-23 79 views
3

這是一個鎖, 只有一個執行線程在 時間。試圖通過另一個執行線程獲取鎖 使 處於後一循環狀態,直到鎖定爲 發佈。如何在引擎蓋下實施自旋鎖定?

它是如何處理兩個線程試圖獲取鎖完全相同的時間

我想這個問題也適用於各種其他的互斥體實現。

回答

2

取決於處理器和線程實現。大多數處理器的指令都可以以原子方式執行,最重要的是你可以創建自旋鎖等。例如,IA-32有一個xchg指令來進行原子交換。然後,您可以實現一個天真的自旋鎖,如:

eax = 1; 
    while(xchg(eax, lock_address) != 0); 
    // now I have the lock 
    ... code ... 
    *lock_address = 0; // release the lock 
+0

同樣,這取決於處理器架構。 'xchg'的實現是一個微碼/硬件問題。最終,即使在多個處理器/內核共享一個總線和一個時鐘的情況下,也不會在同一時間發生任何事情。應該可以找到針對特定處理器的這些指令之一的控制路徑(SPARC可能是最簡單的),但不太可能存在一般適用的特定答案。 – 2010-05-23 13:59:50

+0

因此,最終鎖定的實現是基於事實上在同一時間沒有發生任何事情? – httpinterpret 2010-05-23 14:11:35

+1

說「沒有什麼事情發生在同一時間」在某種意義上說是我的誇大。相反,有些事情不可能與自己同時發生。一個例子可能是,例如你有一臺32位內存的機器。兩個處理器不能同時將第0位翻轉,只有一個邏輯線通向該位(觸發器或其他)。在這些屬性的基礎之上,像'xchg'這樣的東西被構建,並且像'xchg',spinlocks,mutexes等東西被構建。 – 2010-05-23 14:30:40

6

正如以前的海報表明,每一個現代化的機器類型有一類特殊的被稱爲「原子學」那些作爲以前的海報操作指令的指示......他們連載至少執行指定的內存位置。

在x86上,存在一個LOCK彙編器前綴,它向機器指示應該以原子方式處理下一條指令。遇到這條指令時,x86上會有幾件事發生。

  1. 等待的讀取預取被取消(這意味着CPU不會將數據呈現給可能在原子上過時的程序)。
  2. 等待寫入內存的刷新。
  3. 該操作執行,保證自動和序列化對其他CPU。在這種情況下,「序列化」意味着「它們一次發生一次」。從原則上來說,「這條指令的所有部分都是在沒有任何干預的情況下發生的」。

對於x86,有兩個常用指令用於實現鎖定。

  1. CMPXCHG。有條件的交換。僞代碼:
 
uint32 cmpxchg(uint32 *memory_location, uint32 old_value, uint32 new_value) { 
    atomically { 
     if (*memory_location == old_value) 
      *memory_location = new_value; 
     return old_value; 
    } 
} 
  • XCHG。僞代碼:
  •  
    uint32 xchg(uint32 *memory_location, uint32 new_value) { 
        atomically { 
         uint32 old_value = *memory_location; 
         *memory_location = new_value; 
         return *old_value; 
        } 
    } 
    

    所以,可以實現這樣的鎖:

     
    uint32 mylock = 0; 
    while (cmpxchg(&mylock, 0, 1) != 0) 
        ; 
    

    我們旋轉,等待鎖,因此,自旋鎖。

    現在,解鎖說明不會顯示這些很好的行爲。根據您使用的機器和解鎖的說明,可以觀察到各種違反一致性的情況。例如,即使在x86,其中有一個非常友好的內存一致性模型,下面可以觀察到:

     
        Thread 1  Thread 2 
        mov [w], 0 mov [x], 0 
        mov [w], 1 mov [x], 2 
        mov eax, w mov eax, x 
        mov [y], eax mov [z], eax 
    

    在這個節目的最後,Y和Z都可以有值0!

    無論如何,最後一個註釋:x86上的LOCK可以應用於ADD,OR和AND,以便獲得指令的一致和原子讀 - 修改 - 寫語義。這對設置標誌變量並確保它們不會丟失很重要。沒有這個,你有這個問題:

     
        Thread 1  Thread 2 
        AND [x], 0x1 AND [x], 0x2 
    

    在這個程序結束時,x的可能值是1,2和0x1 | 0x2(3)。爲了得到一個正確的計劃,你需要:

     
        Thread 1   Thread 2 
        LOCK AND [x], 0x1 LOCK AND [x], 0x2 
    

    希望這會有所幫助。

    +1

    我想在你的cmpxchg()的定義中,你會想要返回內存位置的實際值。從https://en.wikipedia.org/wiki/Compare-and-swap,「操作的結果必須表明它是否執行了替換;這可以通過返回從內存位置讀取的值來完成(而不是寫入它的價值)。「 – user674669 2012-11-04 20:05:38