2013-02-18 45 views
0

我有升壓自旋鎖碼的一些問題:約自旋鎖

class spinlock 
{ 
public: 
    spinlock() 
     : v_(0) 
    { 
    } 

    bool try_lock() 
    { 
     long r = InterlockedExchange(&v_, 1); 
     _ReadWriteBarrier();  // 1. what this mean    
     return r == 0; 
    } 

    void lock() 
    { 
     for (unsigned k = 0; !try_lock(); ++k) 
     { 
      yield(k); 
     } 
    } 

    void unlock() 
    { 

     _ReadWriteBarrier();      
     *const_cast<long volatile*>(&v_) = 0; 
     // 2. Why don't need to use InterlockedExchange(&v_, 0); 
    } 

private: 
    long v_; 
}; 
+0

好,開鎖是無條件的... – 2013-02-18 09:17:18

+0

@KerrekSB此外,先驗的,如果你調用'unlock',你有鎖,'v_'只能是'1'。 – 2013-02-18 09:18:48

回答

1
  1. 一個ReadWriteBarrier()是一個「記憶障礙」(在這種情況下讀取和寫入),一個特殊的指令給處理器以確保導致存儲器操作的任何指令已經完成(load & store操作 - 或在例如x86處理器,其在每一側有一個存儲器的操作數的任何opertion)。在這種情況下,要確保InterlockedExchange(&v_,1)已經完成,然後再繼續。

  2. 因爲一個InterlockedExchange將是效率較低(需要更多的互動與機器的任何其他內核,以確保其他所有的處理器內核都「放手」的價值 - 這是沒有意義的,因爲最有可能(在正常工作代碼)我們只unlock如果我們實際持有的鎖,所以沒有其他的處理器將有不同的值比緩存我們寫什麼了反正),和volatile寫入到內存會一樣好。

+0

我以爲InterlockedExchange是一個完整的讀/寫屏障? – ronag 2013-02-18 09:20:50

+0

既然你提到x86--不是x86強烈的排序,所以內存屏障是隱含的?我相信代碼主要在x86上充當*編譯器*障礙,沒有額外的機器代碼。 – 2013-02-18 09:21:13

+0

我不清楚它是否實際上導致了指令: http://msdn.microsoft.com/en-us/library/f20w0x5e%28v=vs.80%29.aspx – 2013-02-18 09:23:43

0

的障礙是有保證的內存同步;沒有 他們,不同的線程可能會看到 不同的命令修改內存。

並且InterlockedExchange在第二種情況下不是必需的 ,因爲我們對先前的值不感興趣。的 InterlockedExchange作用是無疑要設置的值,並返回 以前的值。 (爲什麼v_long,何時能 只能採取價值01,是超越我。)

+0

如果'InterlockedExchange'只存在'long',該怎麼辦? – 2013-02-18 09:18:17

+0

那麼圖書館的作者不是很好。事實上,我預計會有相反的結果:'InterlockedExchange'需要一個可以自動訪問的類型。在我工作的很多平臺上,「長」不能自動訪問。 (在某些情況下,沒有比'char'更大的原子地訪問。) – 2013-02-18 09:48:22

+0

這是Windows,對不對?我不太瞭解它,但我認爲他們會選擇一種原子的類型(可能稱爲「LONG」或「ZKLNGSZINT」或其他方便的東西)。 – 2013-02-18 09:59:40

0

有三個問題與原子訪問變量。首先,確保在讀或寫值的過程中沒有線程切換;如果發生這種情況,稱爲「撕裂」;第二個線程可以看到一個部分寫入的值,這通常是無意義的。其次,確保所有處理器都能看到正在寫入的變化,或者處理器讀取值可以看到以前對該值的任何更改;這被稱爲「緩存一致性」。第三,確保編譯器不會將代碼跨讀取或寫入;這被稱爲「代碼運動」。 InterlockedExchange做前兩個;雖然MSDN文檔相當混亂,但_ReadWriteBarrier做了第三個,也可能是第二個。