当前位置: 首页 > 编程语言 > C#

在.Net中使用Dictionary实现线程安全共享

时间:2023-04-10 23:08:54 C#

在.Net中使用Dictionary实现线程安全我有这个函数:staticDictionaryKeyValueDictionary=newDictionary();staticvoidIncreaseValue(intkeyId,intadjustment){if(!KeyValueDictionary.ContainsKey(keyId)){KeyValueDictionary.Add(keyId,0);}KeyValueDictionary[keyId]+=调整;我本来以为这不是线程安全的。但是,到目前为止,在测试它时,同时从多个线程调用它时,我还没有看到任何异常。我的问题:它是线程安全的还是我到目前为止很幸运?如果它是线程安全的,那为什么呢?但是,到目前为止,在测试它时,同时从多个线程调用它时,我还没有看到任何异常。它是线程安全的还是我到目前为止很幸运?如果它是线程安全的,那为什么呢?你很幸运。这些线程错误很容易产生,因为测试会给您一种错误的安全感,即您正在做正确的事情。事实证明,当您有多个编写者时,Dictionary不是线程安全的。文档明确指出:只要不修改集合,字典就可以同时支持多个读者。即便如此,枚举集合本身并不是一个线程安全的过程。在枚举与写访问权争用的极少数情况下,必须在整个枚举过程中锁定集合。要允许多个线程访问一个集合进行读写,您必须实现自己的同步。或者,使用ConcurrentDictionary。但是,您仍然必须编写正确的代码(请参阅下面的注释)。除了缺乏线程安全性之外,您很幸运能够避免使用Dictionary,您的代码还存在危险的缺陷。以下是您如何弄错代码:staticvoidIncreaseValue(intkeyId,intadjustment){if(!KeyValueDictionary.ContainsKey(keyId)){//AKeyValueDictionary.Add(keyId,0);}KeyValueDictionary[keyId]+=调整;字典是空的。线程1进入keyId=17的方法。由于Dictionary为空,if的条件返回true,线程1到达标记为A的代码行。线程1暂停,线程2进入keyId=17的方法。由于Dictionary为空,if的条件返回true,线程2到达标记为A的代码行。线程2被挂起,线程1被恢复。现在,线程1将(17,0)放入字典中。线程1已暂停,现在线程2已恢复。现在线程2尝试将(17,0)添加到字典中。由于密钥违规引发异常。还有其他可能发生异常的情况。例如,线程1可以在加载KeyValueDictionary[keyId]的值时暂停(假设它加载keyId=17,并获得值42),线程2可以介入并修改该值(假设它加载keyId=17,添加调整27),现在线程1恢复并将其调整添加到它加载的值(特别是,它没有看到线程2对与keyId=17关联的值的修改!)。请注意,即使使用ConcurrentDictionary也会导致上述错误!由于与Dictionary的线程安全或缺乏线程安全无关的原因,您的代码不安全。要使用并发字典使您的代码线程安全,您必须说:KeyValueDictionary.AddOrUpdate(keyId,adjustment,(key,value)=>value+adjustment);这里我们使用ConcurrentDictionary.AddOrUpdate。它不是线程安全的,但不进行检查,因此静默损坏可能不会引起注意。它似乎在很长一段时间内都是线程安全的,因为只有在需要rehash()时才有可能发生异常。否则,它只会破坏数据。.NET库有一个线程安全的字典,ConcurrentDictionaryhttp://msdn.microsoft.com/en-us/library/dd287191.aspx更新:我没有完全回答这个问题,所以这里有一个包含更多答案的更新确切地提出问题。根据MSDN:http://msdn.microsoft.com/en-us/library/xfhwa508.aspxDictionary可以支持多人同时阅读,只要不修改合集。即便如此,枚举集合本身并不是一个线程安全的过程。在枚举与写访问权争用的极少数情况下,必须在整个枚举过程中锁定集合。要允许多个线程访问一个集合进行读写,您必须实现自己的同步。有关线程安全的替代方法,请参阅ConcurrentDictionary。此类型的公共静态(在VisualBasic中为共享)成员是线程安全的。到目前为止你很幸运。它不是线程安全的。来自词典文档...只要不修改集合,词典就可以同时支持多个读者。即便如此,枚举集合本身并不是一个线程安全的过程。在枚举与写访问权争用的极少数情况下,必须在整个枚举过程中锁定集合。要允许多个线程访问一个集合进行读写,您必须实现自己的同步。以上就是C#学习教程:UsingDictionaryin.Netforthreadsafety分享的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文来自网络收藏,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: