Is this using a dictionary streamed or not?
Here are my two variants of a method that returns a string associated with an enumeration value (stored in a dictionary). The first option is slower but thread safe, the second is faster but I don't know if it is thread safe or not. Firstly:
string GetStringForEnum (SomeEnum e)
{
string str = null;
lock (someDictionary) //someDictionary is not used anywhere else (only in this method)
{ if (!someDictionary (e, out str)) { someDictionary.Add (e, "somehowCreatedString"); }
return str;
}
Second option:
string GetStringForEnum (SomeEnum e)
{
string str = null;
if (!someDictionary (e, out str))
{
lock (someDictionary) //someDictionary is not used anywhere else (only in this method)
{ if (!someDictionary (e, out str)) { someDictionary.Add (e, "somehowCreatedString"); }
}
return str;
}
The second option is not used "locking" every time, but is it thread safe or not?
source to share
There are two problems here:
-
lock (someDictionary)
- this is not recommended, even if the dictionary is not used elsewhere. This is a theoretical argument, but the (future) Dictionary class code might block on its own. -
if (!someDictionary (e, out str))
without blocking. I guess this is a challengeTryGetValue()
. It's just not safe, your Read could be interrupted by writing on another thread. This can result in all kinds of errors (index out of range, null reference). Errors will be very rare (= difficult to reproduce).
source to share
documentation on Dictionary
contains safety profile streams:
A
Dictionary(Of TKey, TValue)
can support multiple readers at the same time as long as the fee is not changed . Even so, enumerating through a collection is inherently not a thread-safe procedure. In the rare case that an enumeration is associated with an access record, the collection should be blocked during the entire enumeration. To allow read and write access to a collection by multiple threads, you must implement your own synchronization.For an alternative other than the flux. See
ConcurrentDictionary(Of TKey, TValue)
.
So:
-
TryGetValue
is safe to use from multiple threads because it is read-only. However, it is unsafe when other code is writing the dictionary at the same time (which is what your code does). - Adding a value is never safe unless you lock the dictionary.
- Usage
ConcurrentDictionary
is an easy transition solution, but it might not be any faster than your first version (I assume it will block for every operation).
And a side note: using a field that is not private (here is a field someDictionary
and we don't know if it is private
or not) as the goal is lock
not recommended, since in theory external code could also make a decision lock
without you knowing (in practice it won't, but why not and theoretically not correct?).
source to share