我正在阅读(考虑编写我自己的线程安全字典)我找到了以下实现。
http://devplanet.com/blogs/brianr/archive/2008/09/26/thread-safe-dictionary-in-net.aspx
一般看起来很不错,但有一件事让我感到困惑。
以下内容: 无法枚举线程安全字典。相反,枚举键或值集合
可以在
中找到public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
throw new NotSupportedException("Cannot enumerate a threadsafe dictionary. Instead, enumerate the keys or values collection");
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotSupportedException("Cannot enumerate a threadsafe dictionary. Instead, enumerate the keys or values collection");
}
我没有得到的是为什么可以枚举键或值,而不是字典的kvp?
有人可以为我阐明这一点吗?提前谢谢。
答案 0 :(得分:4)
SO用户和MS员工JaredPar在他的博客上有一个关于构建线程安全集合的简短系列,绝对值得您花时间:
<强> [更新:] 强>
再读一遍,如果你的时间不够,那么第二篇文章可能就是它自己的。
总结一下:您发现在线发布的大多数“线程安全”集合通常要么不是非常有用,要么一次只有线程安全的一个操作,使“{1}}或.Count
等”决策“成员无用(到下一行代码运行时,它们“陈旧”。
答案 1 :(得分:2)
我可以直接回答这个问题,因为我写了那本字典:)
在字典上获取枚举器将获得对内部KVP集的引用。你必须保持读锁定,直到你完成枚举,这可能需要很长时间。
我说要枚举键或值的原因是我在请求时复制键和值列表,因此我没有返回对词典内部列表的引用,如果你改变了锁定,可能会导致问题。虽然,我想你也可以在KVP上实现相同的模式,因为它们是只读的。
public virtual ICollection<TKey> Keys
{
get
{
using (new ReadOnlyLock(this.dictionaryLock))
{
return new List<TKey>(this.dict.Keys);
}
}
}
public virtual ICollection<TValue> Values
{
get
{
using (new ReadOnlyLock(this.dictionaryLock))
{
return new List<TValue>(this.dict.Values);
}
}
}
答案 2 :(得分:1)
当您枚举KVP集合时,您正在进入和退出整个字典的锁定。因此,在枚举的循环体中,您不在锁中,并且更改KVP可能会导致竞争条件。