簡體   English   中英

這是否使用字典線程安全?

[英]Is this using of dictionary thread-safe or not?

這是我的兩個方法變體,它返回一個字符串,與枚舉值相關聯(保存在字典中)。 第一個變體較慢,但線程安全,第二個變體更快,但我不知道它是否是線程安全的。 第一的:

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

第二種變體:

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

第二種變體不是每次都使用“鎖”,但它是否是線程安全的?

這里有兩個問題:

  • lock (someDictionary) - 這是不建議的,即使字典沒有在其他地方使用。 這是一個理論上的爭論,但字典 class 的(未來)代碼可能會鎖定自己。

  • if (,someDictionary (e, out str))沒有鎖。 我假設這是對TryGetValue()的調用。 這根本不是線程安全的,您的讀取可能會被另一個線程中的寫入中斷。 這可能會以各種錯誤結束(索引超出范圍,null 參考)。 錯誤將非常罕見(= 難以重現)。

Dictionary上的文檔有一個關於線程安全的部分:

只要集合未被修改Dictionary(Of TKey, TValue)就可以同時支持多個讀者。 即便如此,通過集合進行枚舉本質上不是線程安全的過程。 在枚舉與寫訪問爭用的極少數情況下,必須在整個枚舉期間鎖定集合。 要允許多個線程訪問集合以進行讀寫,您必須實現自己的同步。

有關線程安全的替代方法,請參閱ConcurrentDictionary(Of TKey, TValue)

所以:

  • TryGetValue是只讀的,因此可以安全地從多個線程使用。 但是,當其他代碼同時寫入字典(您的代碼正在這樣做)時,這是不安全的。
  • 添加一個值永遠不會安全,除非你鎖定字典。
  • 使用ConcurrentDictionary是一個簡單的解決方案,但它可能不會比您的第一個版本快(我假設它會鎖定每個操作)。

附注:不建議使用非私有字段(這里的字段是someDictionary ,我們不知道它是否是private的)作為lock目標,因為理論上外部代碼也可以在您不知情的情況下決定lock它(實際上這不會發生,但為什么在理論上也不正確呢?)。

如果使用 .NET 4,則可以使用ConcurrentDictionary來確保線程安全。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM