3

I was just testing how ConcurrentDictionary works. We know that it is thread safe. So I create two tasks and run both task simultaneously. first task adds data to ConcurrentDictionary and the second task reads data from it. The output I got was bit weird.

Here is my program code:

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();

    Task t1 = Task.Factory.StartNew(() =>
    {
        for (int i = 0; i < 10; ++i)
        {
            dictionary.TryAdd(i.ToString(), i.ToString());
            Console.WriteLine("Adding  - > " + i.ToString());
            Thread.Sleep(100);
        }
    });

    Task t2 = Task.Factory.StartNew(() =>
    {
        Thread.Sleep(300);
        foreach (var item in dictionary)
        {
            Console.WriteLine("Reading - > " + item.Key );
            Thread.Sleep(150);
        }
    });

    try
    {
        Task.WaitAll(t1, t2);
    }
    catch (AggregateException ex)
    {
        Console.WriteLine(ex.Flatten().Message);
    }
    Console.ReadLine();
}

Output screenshot: enter image description here

My question: As you can see from the screenshot, the data is being added sequential, but the reading is not sequential. Why is this happening?

waka
  • 3,362
  • 9
  • 35
  • 54
Monojit Sarkar
  • 2,353
  • 8
  • 43
  • 94
  • 4
    Why "adding data is sequential" is pretty obvious: because you're calling the method in that order. Why the read order is random is simply because the ConcurrentDictionary gives no guarantee whatsoever on that point. The order in which the data is returned is an implementation detail and shouldn't be relied upon – Kevin Gosse Jan 25 '18 at 12:52
  • None of the Concurrent* classes guarantee order. A dictionary is not a sequence. – Colin Mackay Jan 25 '18 at 12:52
  • 1
    Dictionary keys are inherently not ordered. Relying on an enumeration for *any* dictionary type to give you back keys in order is wrong, concurrent or not. (The exception being `SortedDictionary`, of course.) Note that even if the order *was* guaranteed, your code would still be "wrong" in the sense that enumerating the keys could get any number of keys -- including none at all -- because the tasks are not synchronized. (The `Sleep` calls prevent this in practice, but not in theory.) – Jeroen Mostert Jan 25 '18 at 12:54
  • The reading isn't "random", though. If you step through the code with debugger, you'd see that up until the for loop reaches `7` all items get added at the beginning of the dictionary, after that it gets added at the end (at least this is the case for me when I run it). Why this happens I don't know. But reading from the dictionary isn't "random", it steps through every item in the order it was added to the collection. – waka Jan 25 '18 at 13:03
  • thanks all for suggestion and comments. – Monojit Sarkar Jan 25 '18 at 13:10

0 Answers0