[英]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.