Is this using of dictionary thread-safe or not?

北战南征 提交于 2019-12-23 18:53:09

问题


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?


回答1:


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




回答2:


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




回答3:


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



来源:https://stackoverflow.com/questions/10007155/is-this-using-of-dictionary-thread-safe-or-not

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!