2011-08-14 80 views
4

在延續了我對C#和.NET鎖最新的幾點思考,C#鎖定機制 - 只寫鎖定

考慮以下情形:

我有一個包含一個特定的集合(本例中的一類,我用了一個Dictionary<string, int>),這是從一個數據源使用它的身體,你可以看到下面的具體方法每隔幾分鐘更新:

DataTable dataTable = dbClient.ExecuteDataSet(i_Query).GetFirstTable(); 

    lock (r_MappingLock) 
    { 
     i_MapObj.Clear(); 

     foreach (DataRow currRow in dataTable.Rows) 
     { 
      i_MapObj.Add(Convert.ToString(currRow[i_Column1]), Convert.ToInt32[i_Column2])); 
     } 
    } 

r_MappingLock是專門鎖定關鍵部分,其刷新的對象dicti onary的內容。

i_MapObj是字典對象

i_Column1和i_Column2是含有用於映射所需數據的數據表的列名稱。

現在,我也有一個類方法,它接收一個字符串並根據提到的字典返回正確的映射int。

我想這種方法要等到刷新方法完成它的執行,所以乍一看會認爲下面的實現:

lock (r_MappingLock) 
    { 
     int? retVal = null; 

     if (i_MapObj.ContainsKey(i_Key)) 
     { 
      retVal = i_MapObj[i_Key]; 
     } 

     return retVal; 
    } 

這將防止意外行爲和返回值,而詞典被更新,但會出現另一個問題: 由於每個執行上述方法的線程都會嘗試聲明該鎖,這意味着如果多個線程同時嘗試執行此方法,則每個線程都必須等到上一個線程完成執行方法並嘗試聲明鎖定,這顯然是一種不良行爲,因爲上述方法僅適用於閱讀的目的。

我正在考慮向將被設置爲true或false的類中添加一個布爾成員以更新或不更新字典並在「只讀」方法中對其進行檢查,但這會產生其他基於種族條件的問題...

任何想法如何優雅地解決這個問題?再次

感謝,

米奇

回答

8

看看內置的ReaderWriterLock

+0

太棒了,正是我所需要的... –

+2

@Mikey請務必閱讀有關它的問題和ReaderWriterLockSlim –

+0

您可以發表一些相關的鏈接嗎? –

4

我只是切換到使用一個ConcurrentDictionary完全避免這種情況 - 手動鎖定容易出錯。同樣,我可以從"C#: The Curious ConcurrentDictionary"收集,ConcurrentDictionary已被讀取優化。

+0

的併發集合是非常好的,如果你是在.NET 4 –

+0

我在.NET 4中,但我實際上更感興趣的是解決方案的理論思想以及適合舊版.NET的解決方案,謝謝! –

0

在C#4.0中有更快的ReaderWriterLockSlim類! 幾乎和鎖一樣快()。

保持策略不允許遞歸(LockRecursionPolicy :: NoRecursion)以保持性能如此之高。

Look at this page for more info.

+0

'ReaderWriterLockSlim'自3.5以來一直在框架中... –

1

你可能會考慮更新,而不是鎖定時,創建一個新的字典。這樣一來,你將永遠有一致的結果,但在讀取更新將返回先前的數據:

private volatile Dictionary<string, int> i_MapObj = new Dictionary<string, int>(); 

private void Update() 
{ 
    DataTable dataTable = dbClient.ExecuteDataSet(i_Query).GetFirstTable(); 

    var newData = new Dictionary<string, int>(); 
    foreach (DataRow currRow in dataTable.Rows) 
    { 
     newData.Add(Convert.ToString(currRow[i_Column1]), Convert.ToInt32[i_Column2])); 
    } 

    // Start using new data - reference assignments are atomic 
    i_MapObj = newData; 
} 

private int? GetValue(string key) 
{ 
    int value; 
    if (i_MapObj.TryGetValue(key, out value)) 
     return value; 

    return null; 
}