当使用a HashSet<string>检查时,是否之前处理过一个项目(即仅使用Add和Contains使用).此外,当Contains返回false时,它是不相关的,即使它是在之前添加的...
我没有锁定遇到以下异常:
[IndexOutOfRangeException:索引超出了数组的范围.] System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)+6108128
仅锁定Add调用是否足够?
以下似乎永远有效 - 但这不是证据......
HashSet<string> hashSet = new HashSet<string>();
Parallel.ForEach(GetString(), h =>
{
hashSet.Contains(h);
lock(hashSetLock)
{
hashSet.Add(h);
}
hashSet.Contains(h);
});
Run Code Online (Sandbox Code Playgroud)
为了使其精确:我知道Contains没有锁定就可以进行线程安全.如果上面的代码可能抛出异常或者可能破坏底层数据结构的内部状态(= HashSet),那么我的问题是(接受误报).
不,仅仅锁定是不够的Add.
它不会崩溃的事实只会告诉您它在测试期间没有崩溃.
你无法保证:
如果以多线程方式使用,则非线程安全数据结构无法保证.
你需要:
如果使用与散列集不同的数据结构(如字典),您甚至可能需要锁定多语句,因为这可能仍然会失败:
lock (dLock)
if (d.ContainsKey("test"))
return;
var value = ExpensiveCallToObtainValue();
lock (dLock)
d.Add("test", value);
Run Code Online (Sandbox Code Playgroud)
在调用ContainsKey和调用Add另一个线程之间可能已经插入了该键.
要在不使用线程安全数据结构的情况下正确处理此问题,请在同一个锁中包含两个操作:
lock (dLock)
{
if (!d.ContainsKey("test"))
d.Add("test", ExpensiveCallToObtainValue());
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2988 次 |
| 最近记录: |