user3359453
user3359453

Reputation: 359

Synchronization issue while updating element in ConcurrentDictionary

I have this code, where I am trying to update item(which is a list) in my concurrent dictionary for a key (key is same all the time).

Here is my code -:

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;
                }


            });

        }
    }

one out of 10 times above code is throwing exception - "Source array was not long enough. Check srcIndex and length, and the array's lower bounds."

I know this is a synchronization issue of list , but I am not getting why is this coming , since ConcurrentDictionary is thread safe. so I assume, it lets only one thread to update my list at one time, so there should not be any problem-:

I know I am missing something - suggestions please -:

Upvotes: 0

Views: 374

Answers (1)

Taukita
Taukita

Reputation: 178

ConcurrentDictionary can be thread-safe, but List is not.

Look at decompiled method from List:

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

Thread #1 and Thead #2 can pass if (this._size == this._items.Length) at the same time. Thread #1 will set value here this._items[this._size++] = item;, but Thread #2 will cause IndexOutOfRangeException. You need thread-safe list.

update You can use SynchronizedCollection instead of List

Upvotes: 4

Related Questions