使用 HashSet< string> 进行检查时,是否曾处理过某项(即仅 Add 和包含)。而且,当Contains返回false时,即使它是在...之前添加的,也没有关系。
When using a HashSet<string> to check, whether an item was handled before (i.e. only Add and Contains is used). Furthermore it is not relevant, when Contains returns false, even though it was added before ...
我遇到了以下未锁定的异常:
I encountered following exception without locking:
[IndexOutOfRangeException:索引超出数组的范围。] System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)+6108128
[IndexOutOfRangeException: Index was outside the bounds of the array.] System.Collections.Generic.HashSet`1.AddIfNotPresent(T value) +6108128
仅锁定添加调用就足够了吗?
Is it sufficient, to lock only the Add call?
以下似乎永远有效-但这不是证明...
Following seems to work forever - but that is not a proof...
HashSet<string> hashSet = new HashSet<string>(); Parallel.ForEach(GetString(), h => { hashSet.Contains(h); lock(hashSetLock) { hashSet.Add(h); } hashSet.Contains(h); });准确地说:我知道调用包含不带锁。我的问题是(接受错误肯定)以上代码是否可能引发异常或破坏基础数据结构(= HashSet)的内部状态。
To make it precise: I know that it is not thread-safe to call Contains without a lock. My question is (accepting false positives) if the above code could throw an exception or could destroy the internal state of the underlying data structure (=HashSet).
推荐答案否,仅锁定 Add 是不够的。
事实它不会崩溃只是告诉您它在测试期间没有崩溃。
The fact that it doesn't crash only tells you that it didn't crash during your test.
您不能保证:
- 将来不会崩溃
- 它将产生正确的结果
非线程安全的数据结构不能保证以多线程方式使用。
A non-threadsafe data structure has no guarantees whatsoever if used in a multithreaded fashion.
您需要:
- 每次调用时锁定
- 使用线程安全数据结构,该结构已构建为支持此方案
如果您使用的数据结构与哈希集不同,例如字典,则可能甚至需要锁定多语句,因为可能仍然失败:
If you use a different data structure than a hashset, like a dictionary, you may even need to lock multi-statements, because this may still fail:
lock (dLock) if (d.ContainsKey("test")) return; var value = ExpensiveCallToObtainValue(); lock (dLock) d.Add("test", value);在 ContainsKey 的调用与调用之间添加另一个线程可能已经插入了该键。
Between the call to ContainsKey and the call to Add another thread may have already inserted that key.
要正确处理此问题,而无需使用线程安全的数据结构,将两个操作都包含在同一锁内:
To handle this correctly, without using a threadsafe data structure, is contain both operations inside the same lock:
lock (dLock) { if (!d.ContainsKey("test")) d.Add("test", ExpensiveCallToObtainValue()); }更多推荐
锁定HashSet并发
发布评论