简体   繁体   中英

Is this using of dictionary thread-safe or not?

Here is two my variants of method, which returns a string, associated with enum value (kept in dictionary). First variant is slower, but thread-safe, second is faster, but i don't know, whether it is thread-safe or not. First:

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 variant:

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

Second variant is not used "lock" each time, but is it thread-safe or not?

There are 2 problems here:

  • lock (someDictionary) - this is dis-advised, even if the dictionary is not used elsewhere. It is a theoretical argument but the (future) code of the Dictionary class could lock on itself.

  • if (,someDictionary (e, out str)) without a lock. I assume this is a call to TryGetValue() . This simply is not thread-safe, your Read could be interrupted by a Write in another thread. This could end in all sorts of errors (index out of range, null reference). The errors will be very rare (= hard to reproduce).

The documentation on Dictionary has a section on thread safety:

A Dictionary(Of TKey, TValue) can support multiple readers concurrently, as long as the collection is not modified . Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

For a thread-safe alternative, see ConcurrentDictionary(Of TKey, TValue) .

So:

  • TryGetValue is safe to use from multiple threads because it is read-only. However, it is not safe when other code is writing the dictionary at the same time (which your code is doing).
  • Adding a value is never safe unless you lock the dictionary.
  • Using a ConcurrentDictionary is an easy solution to get going, but it may be no faster than your first version (I assume it's going to lock on every operation).

And a side note: Using a field that is not private (here the field is someDictionary and we don't know if it's private or not) as a lock target is not recommended because theoretically external code could also decide to lock it without your knowledge (practically this is not going to happen, but why not be theoretically correct as well?).

If you use .NET 4 you can use ConcurrentDictionary for thread safety.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM