2012-09-11 63 views
0
public class MyConfigurationData 
{ 
    public double[] Data1 { get; set; } 
    public double[] Data2 { get; set; } 
} 
public class MyClass 
{ 
    private static object SyncObject = new object(); 
    private static MyConfigurationData = null; 
    private static MyClass() 
    { 
     lock(SyncObject) 
     { 
     //Initialize Configuration Data 
     //This operation is bit slow as it needs to query the DB to retreive configuration data 
     } 
    } 
    public static MyMethodWhichNeedsConfigurationData() 
    { 
     lock(SyncObject) 
     { 
      //Multilple threads can call this method 
      //I lock only to an extent where I attempt to read the configuration data 
     } 
    } 
} 

在我的應用程序只需要一次幾多次創建配置數據,並使用它。換句話說,我寫一次並閱讀很多次。而且,我想確保在寫操作完成之前不應該發生讀取。換句話說,我不想將MyConfigurationData讀爲NULL。有沒有辦法實現一個無鎖定靜態配置數據?

我知道什麼是靜態構造函數是一個AppDomain只能調用一次。但是,當我準備配置數據時,如果有線程試圖讀取這些數據,我將如何確保同步有效?最後,我想提高讀取操作的性能。

我可以實現我的目標在無鎖的方式?

回答

2

只要您只有讀取的數據,它應該已經是線程安全的。當剛剛讀取(明顯的反例可能包括延遲加載)時,很少有數據結構不是線程安全的。請注意,靜態構造函數是由運行時自動同步的,因此您不必關心運行「初始化配置數據」步驟的多個線程。

所以說:只要什麼事也沒發生變異的數據,你已經是安全的。你也可以使其難以得到錯誤的躲在一個不變的界面背後的數據,即

public class ConfigurationData { 
    // or some similar immutable API... 
    public double GetData1(int index) { return data1[index]; } 
    public double GetData2(int index) { return data2[index]; } 

    private readonly double[] data1, data2; 

    public ConfigurationData(double[] data1, double[] data2) { 
     this.data1 = data1; 
     this.data2 = data2; 
    } 
} 

那麼你不需要任何鎖:

public class MyClass 
{ 
    private static MyConfigurationData; 
    private static MyClass() 
    { 
    //Initialize Configuration Data 
     MyConfigurationData = ... 
    //This operation is bit slow as it needs to query the DB to retreive configuration data 
    } 
    public static MyMethodWhichNeedsConfigurationData() 
    {   //Multilple threads can call this method 
     var config = MyConfigurationData; 

    } 
} 

請注意,移除鎖提高並行;它不會改變原始的單線程性能。

那說:我應該建議對靜態數據一般;這使得測試非常困難,並且如果您的需求發生變化,就很難做到像多租戶這樣的事情。這可能是更謹慎的一個配置實例,但是它通入系統的一些形式上下文的。這兩種方法都可以成功使用,但這只是需要注意的一點。

+0

感謝您的解釋。 – Imran

+0

+1。 @Imran,請注意,由於最運行時運行時使用鎖來序列化創建,所以在傳統語義中使用傳統語義(使用巧妙的代碼組織來在代碼中沒有鎖/關鍵部分但最多InterlockedXXXX操作)不需要「無鎖」的靜態對象。 –

+0

@AlexeiLevenkov,我明白了。如果運行時在創建靜態對象期間使用鎖定,我很好。我只關心那些靜態對象的無鎖讀取。 – Imran

4

MSDN

靜態構造用於初始化任何靜態數據,或者執行需要僅一次執行的特定動作。它在創建第一個實例或引用任何靜態成員之前自動調用。

因此,您不需要在代碼中使用lock,它實際上是線程安全的。在引用MyMethodWhichNeedsConfigurationData之前調用您的靜態構造函數。

public class MyClass 
{ 
    private static MyConfigurationData = null; 
    private static MyClass() 
    { 
    } 

    public static MyMethodWhichNeedsConfigurationData() 
    { 
    } 
} 
+0

謝謝,我想仔細檢查我對靜態構造函數的看法是否正確。 – Imran

1

我想你應該使用Singleton模式,並將你的配置初始化邏輯放在「GetInstance」方法中,它將返回你的類的實例。

這樣你就不需要任何鎖定機制來讀取。

+0

我的目標與Singleton模式無關,因爲我不需要創建MyClass的單​​個實例。我想通過靜態方法而不是實例方法來操作靜態配置數據。 – Imran

+0

但你打算「我需要創建配置數據只有一次,並多次使用它」「私人靜態MyClass()」 –

相關問題