2011-07-12 64 views
3

可能重複:
The need for volatile modifier in double checked locking in .NET此雙重檢查鎖是否需要volatile關鍵字才能起作用?

考慮下面的代碼片段,它可以由多個線程同時執行,將需要volatile關鍵字,以確保「真實值'connected總是從內存中讀取而不是緩存? (假設Disconnect()只會被調用一次(即如果它第一次不能正常工作,並且connected的值被讀爲false,則不會再次嘗試))。

public class MyClass 
{ 
    private readonly object syncRoot = new object(); 

    private bool connected; 

    public void Disconnect() 
    { 
     if (connected) 
     { 
      lock (syncRoot) 
      { 
       if (connected) 
       { 
        // log off here 
        // ... 
        connected = false; 
       } 
      } 
     } 
    } 

    public void Connect() 
    { 
     lock (syncRoot) 
     { 
      // blah 
      // blah 
      connected = true; 
     } 
    } 
} 

我的感覺是,如果使用雙重檢查鎖定,然後它需要被標記爲volatile因爲如果讀不正確的值是第一次,那麼它會認爲它實際上是斷開的,並不會進入鎖定語句。我也認爲在這種情況下,雙重檢查鎖定不合適/不會提供任何性能增益,只有正常的鎖才能完成這項工作。

我想有人來證實或否認這些想法。

+0

我已經鏈接了一篇文章,我發現這篇文章對於更好地理解同步問題非常有幫助。簡短的回答是,'lock'語句隱式地在讀和寫上都創建了一個內存屏障,這實際上比volatile更強大。 http://www.albahari.com/threading/part4.aspx –

+0

@亨克 - 感謝 - 它是相似的,但在這個問題它可以是一個空引用或可以是一個引用,但它不會被重新設置爲空。我將編輯此問題以添加Connect方法。 – GarethD

+0

我投票重新提出了這個問題。這*不是*與雙重檢查的鎖定模式完全相同。這個代碼有兩個不同的執行路徑(通過不同的方法調用)*和*,可能會泄露的非託管資源正在運行,這使得這種分析方法變得更加複雜。我不相信'volatile'使得這個代碼安全。 –

回答

-2

你是正確的,volatile關鍵字從內存中,而不是CPU緩存中讀取。但這並不意味着它是線程安全的。將syncLock變量更改爲靜態修改器,以確保跨多個實例的線程安全。這是推薦的方法。

+1

它保證只有一個實例,而這不是問題。 – GarethD

+0

你可以在問題是...的地方添加一個問號嗎? –

+0

另外,被比較的值只是一個實例,如果該值是靜態的,那麼你會想要鎖的靜態。 – pstrjds

1

這是我的理解波動,是的,你會想它。我相信volatile會強制每次讀取值,並且會阻止編譯器緩存值或執行其他優化,導致「正確」值不能從內存中讀取。

Eric Lippert's answer他提及使用的揮發性讀取。

+0

不,你[不想使用volatile](http://www.bluebytesoftware.com/blog/PermaLink,guid,a0484627-c752-45f6-a2ac-414130cb3d2f.aspx) –

+0

@亨克,你能解釋一下爲什麼你不想使用volatile(注意:您提供的鏈接已損壞),我知道很難使其正確,但在這種情況下,我確實想要使用它。 – pstrjds

+0

'volatile'被(不正式)棄用。 'lock'提供了這裏所需的所有障礙(請參閱@ Dan的評論)。鏈接正常,但該網站已關閉。另請參閱http://stackoverflow.com/questions/6164466/a-reproducable-example-of-volatile-usage/6164770#6164770 –

1

倘若連接()方法也使用一個lock (syncRoot)的代碼應在不揮發性工作。

但你不會看到任何好處從DCL這裏,爲什麼要經過的麻煩/風險?

+0

謝謝。你能否詳細說明 - 「代碼應該工作」 - 爲什麼代碼應該正常工作,爲什麼不需要volatile?注意,連接變量的第一次檢查不在鎖內()。 – GarethD

+0

@Gareth:但它在Connect()中的'lock'內部更改,對不對?這就夠了。 –

+0

是的,Connect方法也將它設置在一個鎖內,但是我的感覺是,如果別的東西沒有鎖就讀它,這不會有幫助嗎? – GarethD

相關問題