2012-12-18 178 views
4

我在C#多線程程序中遇到了一個不良行爲。我的一些靜態成員正在其他線程中釋放它們的值,而同一個聲明類型的一些靜態值不會丟失它們的值。C#靜態變量跨線程訪問

public class Context { 
    public Int32 ID { get; set; } 
    public String Name { get; set; } 

    public Context(Int32 NewID, String NewName){ 
     this.ID = NewID; 
     this.Name = NewName; 
    } 
} 

public class Root { 
    public static Context MyContext; 
    public static Processor MyProcessor; 

    public Root(){ 
    Root.MyContext = new Context(1,"Hal"); 

    if(Root.MyContext.ID == null || Root.MyContext.ID != 1){ 
     throw new Exception("Its bogus!") // Never gets thrown 
    } 

    if(Root.MyContext.Name == null || Root.MyContext.Name != "Hal"){ 
     throw new Exception("It's VERY Bogus!"); // Never gets thrown 
    } 

    Root.MyProcessor = new MyProcessor(); 
    Root.MyProcessor.Start(); 
    } 
} 

public class Processor { 
    public Processor() { 
    } 

    public void Start(){ 
     Thread T= new Thread (()=> { 

      if(Root.MyContext.Name == null || Root.MyContext.Name != "Hal"){ 
       throw new Exception("Ive lost my value!"); // Never gets Thrown 
      } 

      if(Root.MyContext.ID == null){ 
       throw new Exception("Ive lost my value!"); // Always gets thrown 
      } 

     }); 
    } 
} 

這是一個線程突變問題,同時使用某些類型的靜態成員?

+5

通常,可變靜態屬性不能很好地與併發性兼容。您可能應該限制該狀態的範圍,或確保在併發訪問時不會修改它。 – Servy

+0

感謝您的回覆,屬性或字段成員?我根據目的在根類中使用了公共字段。 –

+1

我的聲明同樣適用於屬性和字段。它們以某種形式都是可變的公共狀態。 – Servy

回答

6

使用volatile變量volatile改性劑或可替代地使用訪問交錯的變量。

您遇到的問題是,編譯器(以及本機編譯器)可以自由地優化對變量的訪問權限,因爲他認爲沒有它們。所以他可能會將一個變量轉儲到一個寄存器中,而不會重讀它。

爲了避免它,你必須確保變量實際上是真正讀取的。揮發性做到了。聯鎖也可以做到這一點(並允許增加/添加等自動發生)。

哪個更好,你必須決定。兩者都強制將內存屏障放到處理器上,而且這種處理器經常需要花費不菲的成本。我經常使用的一種模式是讓這些對象只讀取大部分,以便我只替換根對象(一個內存屏障)。手動處理記憶障礙(可能的話,閱讀手冊中的關鍵字)是一個很好的解決辦法。不過,它的效率更高 - 取決於你在那裏做了多少等等,這可能是需要的。

+1

謝謝,這對我有幫助。 (RTFM在這裏爲其他人,http://www.albahari.com/threading/part4.aspx)正確的鏈接。 –

+0

Grats。你剛剛畢業高級程序設計。這取決於代碼的複雜程度,可能對於調試非常糟糕。 – TomTom

+0

謝謝,我討厭的唯一事情就是在高級語言中處理這個東西; P –

2

嘗試使用在其上被修改/訪問從多個線程

+0

+0。如果從多個線程修改值,'volatile'可能無法幫助。對於「丟失值」的情況絕對不會有幫助,因爲它不保證讀取大於int32/64的類型的最新值或甚至是consitent值。 –

+1

「'volatile'可能沒有幫助,如果值是從多個線程修改」:正是這就是volatile,確保這個變量是真正更新每個線程試圖訪問它。 – VladL

+1

(BTW所有這些不穩定/互鎖與OP問題無關:))。其實你是對的 - 我的看法並不完全正確('揮發性'給你當前的價值,但沒有辦法確保價值沒有改變)。 OP案例不同 - 包含兩個單獨更新的字段 - 在這種情況下沒有任何可以標記爲「volatile」的東西可以提供一致的行爲。 –

0

多線程應用程序中的共享變量值不確定!您應該在每個共享資源上使用鎖定以避免邏輯中的衝突:

static Readonly Object _lock=new Object(); 
    lock(_lock) 
    { 
    //accessing your shared variable 
    }