Guy*_*Guy 9 .net c# collections thread-safety
我有这个功能:
static Dictionary<int, int> KeyValueDictionary = new Dictionary<int, int>();
static void IncreaseValue(int keyId, int adjustment)
{
if (!KeyValueDictionary.ContainsKey(keyId))
{
KeyValueDictionary.Add(keyId, 0);
}
KeyValueDictionary[keyId] += adjustment;
}
Run Code Online (Sandbox Code Playgroud)
我原本认为这不是线程安全的.但是,到目前为止,在测试它时,我没有看到同时从多个线程调用它时的任何异常.
我的问题:它是线程安全还是我到目前为止幸运?如果它是线程安全的那么为什么?
jas*_*son 22
但是,到目前为止,在测试它时,我没有看到同时从多个线程调用它时的任何异常.
它是线程安全还是我到目前为止幸运?如果它是线程安全的那么为什么?
你很幸运.这些带有线程的bug很容易制作,因为测试可以给你一种错误的安全感,你可以正确地做事.
事实证明,Dictionary<TKey, TValue>当你有多个编写器时,它不是线程安全的.文档明确指出:
A
Dictionary<TKey, TValue>可以同时支持多个读取器,只要不修改集合即可.即便如此,通过集合枚举本质上不是一个线程安全的过程.在枚举与写访问争用的极少数情况下,必须在整个枚举期间锁定该集合.要允许多个线程访问集合以进行读写,您必须实现自己的同步.
或者,使用ConcurrentDictionary.但是,您仍然必须编写正确的代码(请参阅下面的注释).
除了缺乏线程安全性之外Dictionary<TKey, TValue>,您有幸避免使用它,您的代码存在危险的缺陷.以下是您如何获得代码错误:
static void IncreaseValue(int keyId, int adjustment) {
if (!KeyValueDictionary.ContainsKey(keyId)) {
// A
KeyValueDictionary.Add(keyId, 0);
}
KeyValueDictionary[keyId] += adjustment;
}
Run Code Online (Sandbox Code Playgroud)
keyId = 17.由于Dictionary是空的,if返回true和线程1中的条件到达标记的代码行A.keyId = 17.由于Dictionary是空的,if返回true和线程2中的条件到达标记的代码行A.(17, 0)到字典中.(17, 0)到字典中.由于密钥违规而抛出异常.还有其他情况可能发生异常.例如,线程1可以在加载值时暂停KeyValueDictionary[keyId](比如加载keyId = 17,并获取值42),线程2可以进入并修改值(比如加载keyId = 17,添加调整27),现在线程1恢复并添加它调整到它加载的值(特别是,它没有看到线程2对与之关联的值所做的修改keyId = 17!).
请注意,即使使用a ConcurrentDictionary<TKey, TValue>也可能导致上述错误!您的代码不安全,原因与线程安全性无关或缺乏线程安全性Dictionary<TKey, TValue>.
要使用并发字典使代码具有线程安全性,您必须说:
KeyValueDictionary.AddOrUpdate(keyId, adjustment, (key, value) => value + adjustment);
Run Code Online (Sandbox Code Playgroud)
我们在这里使用ConcurrentDictionary.AddOrUpdate.
| 归档时间: |
|
| 查看次数: |
3372 次 |
| 最近记录: |