2010-03-19 28 views
5

我一直在閱讀的答案,similar question,但我還是有點迷茫......亞伯有一個偉大的答案,但是這是我不確定的部分:Interlocked是否保證對C#中其他線程的可見性,還是仍然需要使用volatile?

.. .declaring一個變量volatile使得它對每一個訪問都是不穩定的。以任何其他方式強制執行此行爲是不可能的,因此揮發性的 不能替換爲聯鎖。 這是在其他庫,接口或 硬件可以訪問您的變量並且 隨時更新或最需要最新版本的情況下所需要的。

是否原子操作的Interlocked保障看到所有線程,或者我還是必須使用volatile關鍵字的值,以確保變革的知名度?

這是我的例子:

volatile int value = 100000; // <-- do I need the volitile keyword 
// .... 

public void AnotherThreadMethod() 
{ 
while(Interlocked.Decrement(ref value)>0) 
{ 
    // do something 
} 
} 


public void AThreadMethod() 
{ 
while(value > 0) 
{ 
    // do something 
} 
} 

更新:
我是一個糟糕的運動,我改變了原來的例子,所以這裏要再次重申:

public class CountDownLatch 
{ 
    private volatile int m_remain; // <--- do I need the volatile keyword here? 
    private EventWaitHandle m_event; 

    public CountDownLatch(int count) 
    { 
     Reset(count); 
    } 

    public void Reset(int count) 
    { 
     if (count < 0) 
      throw new ArgumentOutOfRangeException(); 
     m_remain = count; 
     m_event = new ManualResetEvent(false); 
     if (m_remain == 0) 
     { 
      m_event.Set(); 
     } 
    } 

    public void Signal() 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref m_remain) == 0) 
      m_event.Set(); 
    } 

    public void Wait() 
    { 
     m_event.WaitOne(); 
    } 
} 
+0

對多次編輯抱歉... Remus一直是一個很好的運動。感謝您的信息! :) – Kiril 2010-03-19 06:29:40

回答

5

他們做不*需要**波動性,因爲你從來沒有檢查互鎖變量的值。相反,您總是通過互鎖操作檢查返回值返回。混合互鎖操作和普通分配/比較總是導致代碼不正確。

我不確定Reset()函數的意圖是什麼,但是那段代碼在線程間原語中沒有位置:您分配給m_remain,直接檢查m_remain的值,非常糟糕。我強烈建議你把它拿出來:不僅執行不當,而且我非常懷疑需要「重置」櫃檯中期壽命的語義。保持簡單:ctor(將代碼從Reset移入)Signal和Wait是唯一需要的三個操作符,它們與現在一樣正確。

更新編輯完代碼後。

忽略你不應該混合這兩個事實,如果你最終混合它們,那麼是的,仍然需要揮發性。易失性主要是關於IL代碼和生成的JIT代碼,以確保始終從實際內存位置讀取值,並且不會進行優化(如代碼重新排序)。事實上,不相關的代碼使用互鎖操作更新值不影響讀取值的其他部分。如果沒有volatile屬性,編譯器/ JIT可能仍會生成忽略其他地方發生的寫入的代碼,如果寫入是互鎖或直接分配,則無關緊要。

順便說一句,有一些有效的模式可以混合普通的讀取和互鎖操作,但它們通常涉及到Interlocked.CompareExchange和go這樣的操作:讀取當前狀態,根據當前狀態做一些計算,嘗試將狀態替換爲互鎖比較交換:如果成功,罰款,如果不降低計算結果,並返回到步驟1.

+0

嗯,我的文章在編輯之前很有意義lol – 2010-03-19 06:02:38

+0

對不起,我把這個例子備份起來......我真的不是故意欺騙你! :) – Kiril 2010-03-19 06:06:16

+0

所以出去重置功能......它真的沒有任何意義。我認爲這可能對重複使用相同的鎖存器很有用,但它比其他任何事情都增加了更多的困惑。 – Kiril 2010-03-19 06:11:13

1

我認爲System.Threading.Thread.VolatileRead(ref myVariable)可能是你在找什麼。與Interlocked.Increment一起使用可以用來保證更改是原子性的,而且您讀取的值是最新的。

相關問題