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?

+3


source to share


3 answers


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 challenge TryGetValue()

    . 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).

+4


source


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?).

+3


source


If you are using .NET 4 you can use ConcurrentDictionary

for thread safety.

+2


source







All Articles