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