-1

I need to thread-safe way to get each item of the ConcurrentDictionary(string, List)

Does it safety to use the following construction?

foreach (var item in concurrentDict)
{
     var readonlyCollection = item.Value.AsReadOnly();
     //use readonly collection, (I need only Values of the concurrent dictionary)
}

I want to use values of the dictionary safety.

  • 3
    If you do nothing but read, what possible danger can there be? You only run into threading problems when you read and write. –  Dec 19 '17 at 20:59
  • thanks. Can I use foreach (var dictValue in concurrentDictionary.Values) { foreach(item in dictValue) { } } ? – Andrey Misnikov Dec 19 '17 at 21:03
  • It would take less time to just try it and find out (yes you can) –  Dec 19 '17 at 21:04

1 Answers1

0

The foreach part is fine, with the caveat that concurrently added items may or may note be included into the iteration. You wouldn't get an exception, though.

However, you need to be careful with item.Value, which is of type List, because lists are not thread-safe. If another thread modifies a list while you are reading it inside your loop, you may get an exception.

Calling AsReadOnly() on your list does not help, because what you get back is a wrapper for the original list. If reading from the original list inside wrapper throws, so does reading from the wrapper. Moreover, you cannot fix this simply by making a shallow copy of the nested list, because concurrent modification may be performed while you are making a copy.

One approach is to lock the list while you are reading and writing it:

foreach (var item in concurrentDict) {
    List<string> listCopy;
    lock (item.Value) {
        listCopy = item.Value.ToList();
    }
     //use collection copy
}

When a writing thread changes the list inside the dictionary, it needs to perform the same locking:

if (concurrentDict.TryGetValue("mykey", var out list)) {
    lock (list) {
        list.Add("newValue");
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thanks. But if I get only Values of the dictionary in foreach, it's impossible to get an exception, correct? Does it need to convert my list to ReadOnlyCollection in the body or I can be sure that my items won't be changed. – Andrey Misnikov Dec 19 '17 at 21:16
  • @AndreyMisnikov It depends on the writing threads. If they create new lists every time, then put it into `concurrentDict`, and never touch that list's content again, then you don't need to make a copy, and the call to `AsReadOnly` is not necessary. If the writing side modifies lists while they are still inside `concurrentDict` then copying and synchronization would be required. – Sergey Kalinichenko Dec 19 '17 at 21:18