Is the <K, V> dictionary thread safe for reading and adding at the same time?
This question relates to a very specific and common scenario in which a dictionary is used to cache items on demand in a multi-threaded environment. To avoid blocking the stream, it is preferable to test the existing cache element outside the synchronization lock, but if later we need to add an element that is considered to be a record in the dictionary, and therefore most of the recommendations that I read in stackoverflow is that you need to block reading and writing, because the internal state of the dictionary can be changed by calls to add ().
However, by looking at Microsoft AjaxControlToolkit (the scriptObjectBuilder class), the code does execute TryGet () outside of any locks and only blocks adding () new elements to the dictionary. I see how this is possible if the bucket into which the item is placed never changes after adding, but my suspicion is that it is wrong and may be a source of errors.
Thanks.
UPDATE Going through the .Net documentation, I think the model described is really wrong. However, I was wondering if this supported a specific implementation of the dictionary and that AjaxControlToolkit relied on it (which would be doubtful). Studying the code in Reflector, I am sure that this is really wrong, the Dictionary.Resize () method redistributes the number of buckets and moves the bucket elements around, so any stream in the middle of TryGet () can potentially work on unstable data.
UPDATE The defect has already been registered against AjaxControlToolkit on codeplex. Cm:
To answer my question, following some investments: when studying the code for the dictionary, I see that the Dictionary.Resize () method redistributes the number of internal buckets that are used to store data, and redistributes the contents of the bucket so that the elements are in the correct bucket based on their hash code. Thus, any thread in the middle of TryGet () risks working with unstable data.
Alternatively, a possible low-lock approach for the Dictionary class might be to lock the lock only with the Resize () method.
Tess Ferranddes has a great blog post about granularity issues with common dictionaries:
The FindEntry method goes through the dictionary, trying to find the key. If several threads do this at the same time, especially if the dictionary is changed in the meantime, you may end up in an endless loop in FindEntry, which will lead to high processor behavior and the process may hang.
I would say that this is definitely a bug in AjaxControlToolkit and would recommend you raise a bug in CodePlex. It should use ReaderWriteLock (Slim).