2013-05-01 49 views
7

我知道在java中,如果你有多個線程訪問一個未標記爲volatile的變量,你可能會得到一些意想不到的行爲。C#和java的volatile關鍵字的行爲方式是一樣的嗎?

例子:

private boolean bExit; 

while(!bExit) { 
    checkUserPosition(); 
    updateUserPosition(); 
} 

如果標記bExit變量voilatile,這將gaurantee其他線程將看到最新的值。

c#的行爲方式是否一樣?

更新

例如,在C#中,如果你這樣做:

int counter = ...; 

for(...) 
{ 
    new Thread(delegate() 
    { 

     Interlocked.Decrement(ref counter); 
    } 
} 


if(counter == 0) 
{ 
    // halt program 
} 

在上面,在C#中,你必須標記計數器變量揮發性或本會工作如預期?

+1

每個* runtime *(JVM或CLR內存模型)都有一組不同的規則,並且有一些重疊。考慮在兩種語言/運行時間和比較中查找「volatile」的正確(和不正確)用法。 – user2246674 2013-05-01 20:07:54

+0

C#volatile實際上是保留在低內存應用程序中使用的,應該只能用作絕對最後的手段。下面是一些文檔,以C#的形式來看看:http://msdn.microsoft.com/en-us /library/x13ttww7(v=vs.71).aspx – Nomad101 2013-05-01 20:09:08

+1

@ Nomad101 - 我不確定低內存應用程序和volatile關鍵字之間存在什麼關係。 – hatchet 2013-05-01 20:15:46

回答

0

如果標記bExit變量voilatile,這將gaurantee其他 線程將看到最新的值。 c#的行爲是否一樣?


是的,但都取決於你如何訪問共享變量。作爲你的例子,如果你以線程安全的方式訪問變量如Interlocked.Decrement即使沒有使用voilatile也不會成爲問題。

volatile (C# Reference from MSDN)

揮發性關鍵字表示一個字段可能通過 被同時執行多個線程進行修改。聲明爲volatile的字段 不受制於編譯器優化, 假定由單個線程訪問。 這可確保最多的 最新值始終存在於現場

What is the "volatile" keyword used for?

+0

因此,我理解無w/o volatile是正確的,當讀取一個非易失性變量正在更新我的多個線程? – loyalflow 2013-05-01 20:23:35

+1

我讀過volatile,實際上並沒有做很多人認爲它的作用。我建議閱讀http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword – hatchet 2013-05-01 20:27:16

0

你需要小心一點這裏你已經在你的例子選擇了兩個不同的類型。我的一般經驗法則是volatile最適合布爾和其他一切,你可能需要其他類型的同步機制。在C#和java中,使用易失性布爾值在例如停止循環或任務執行,其具有從多個線程能見度:

class Processor 
{ 
    private volatile Boolean _stopProcessing = false; 

    public void process() 
    { 
     do 
     { ... } 
     while (!_stopProcessing); 
    } 

    public void cancel() 
    { 
     _stopProcessing = true; 
    } 
} 

上面將在C#或Java並且在該示例工作volatile關鍵字意味着在處理方法中的讀取將與實際的電流值而不是緩存的值。編譯器或VM可能會選擇否則允許緩存該值,因爲循環進程不會更改_stopProcessing本身。

所以對你的第一個問題的答案是肯定的。

雖然你可以在int上使用volatile,但這隻有在你只讀或寫單個值時纔有用。只要你做了更復雜的事情,例如遞增,你需要一些其他類型的同步,比如你使用互鎖。但在第二個例子中,您仍在讀取計數器的值,而沒有進行任何同步,所以您實際上依賴於其他計數器的使用方式(例如,使用「互鎖」)。

在你的第二個例子中,你仍然最好將你的int標記爲volatile,這樣你再次可以確定你獲得了當前值而不是一些緩存版本。但是單獨使用volatile是不夠的,因爲底部的讀取可能會與標準遞減(counter--)重疊,而不是正確使用Interlocked。