2014-12-03 101 views
0

我有這段代碼,我試圖在併發字典中爲一個鍵(鍵一直都是)更新項目(這是一個列表)。在更新ConcurrentDictionary中的元素時發生同步問題

這裏是我的代碼 - :

class Program 
    { 
     private static readonly ConcurrentDictionary<string, List<int>> s_mapDatatypeToSource = new ConcurrentDictionary<string, List<int>>(); 
     static void Main(string[] args) 
     { 


       try 
       { 
        Parallel.For(0, 10000000, i => AddItemToList(i, "local")); 
       } 
       catch (Exception exception) 
       { 
        Console.WriteLine(string.Format("Exception thrown ...{0}", exception.Message)); 
        Console.ReadLine(); 
        throw; 
       } 

      Console.WriteLine("Completed without exception"); 
      Console.ReadLine(); 

     } 

     private static void AddItemToList(int dataKey, string sourceName) 
     { 
      s_mapDatatypeToSource.AddOrUpdate(sourceName.ToUpperInvariant(), new List<int> { dataKey }, (s, list) => 
      { 

       { 
        list.Add(dataKey); 
        return list; 
       } 


      }); 

     } 
    } 

一個出上面的代碼10次拋出異常 - 「源陣列不夠長檢查SRCINDEX和長度,以及數組的下限。」

我知道這是一個同步問題的列表,但我不明白爲什麼會這樣,因爲ConcurrentDictionary是線程安全的。所以我認爲,它可以讓只有一個線程在同一時間來更新我的名單,所以不應該有任何problem-:

我知道我失去了一些東西 - 建議,請 - :

+0

請以及格式化你的代碼不可讀 – 2014-12-03 06:40:49

+0

GetOrAdd和AddOrUpdate不是原子(線程安全)的MSDN自己說: 此外,雖然ConcurrentDictionary的所有方法是線程安全的,並不是所有的方法都是原子的,特別是GetOrAdd和AddOrUpdate。傳遞給這些方法的用戶委託在字典的內部鎖之外被調用。 (這是爲了防止未知代碼阻塞所有線程。) – user3359453 2016-10-06 02:31:31

回答

4

ConcurrentDictionary可以thread-安全,但列表不是。

看反編譯的方法從表:

public void Add(T item) 
{ 
    if (this._size == this._items.Length) 
    this.EnsureCapacity(this._size + 1); 
    this._items[this._size++] = item; 
    ++this._version; 
} 

線程#1和#THEAD 2可以在同一時間通過if (this._size == this._items.Length)。線程#1將在這裏設置值this._items[this._size++] = item;,但線程#2將導致IndexOutOfRangeException。您需要線程安全列表。

更新可以使用SynchronizedCollection而不是List