【问题标题】:ThreadSafe Dictionary... Key Value Pairs Enumerable? (.net)线程安全字典...键值对可枚举? (。网)
【发布时间】:2010-10-12 12:19:26
【问题描述】:

我正在阅读(考虑编写我自己的线程安全字典)我发现了以下实现。

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?

有人可以帮我解释一下吗?提前致谢。

【问题讨论】:

    标签: c# dictionary


    【解决方案1】:

    SO 用户和 MS 员工 JaredPar 在他的博客上有一个关于构建绝对值得您花时间的线程安全集合的短系列:

    [更新:]
    再读一遍,如果你时间不够,第二篇文章可能会独立存在。

    总而言之:您发现在线发布的大多数“线程安全”集合通常不是很有用,或者一次只能线程安全一个操作,这使得像 .Count.Contains 这样的“决策”成员无用(它们是“下一行代码运行时已过时)。

    【讨论】:

      【解决方案2】:

      当您枚举 KVP 的集合时,您将进入和退出整个字典的锁定。因此,在您的枚举的循环体中,您并未处于锁定状态,更改 KVP 可能会导致竞争条件。

      【讨论】:

        【解决方案3】:

        我可以直接回答这个问题,因为我写了那本字典:)

        获取字典上的枚举器将获得对内部 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 个线程同时尝试枚举,你会将复制的列表存储在哪里?
        • 我的想法更像是,锁定 -> 复制数组 -> 解锁 -> 然后在复制的版本上返回枚举数。
        • 不错的计划。尽管它确实违反了枚举的隐含属性之一,但您正在枚举的列表在枚举期间不应更改。不管怎样,只要明白这一点,我想它不会受到伤害。
        • @BrianRudolph:如果集合被修改,指定枚举器应该总是抛出异常是恕我直言的错误;更好的规范应该是指定如果枚举器不抛出哪些行为应该是可接受的或不可接受的,并指定如果修改集合时不能保证可接受行为的枚举器应该抛出异常而不是做一些不可接受的事情。对于许多类型的集合,抛出异常会比例如更容易。确保整个枚举中存在的每个项目都只返回一次,但是...
        猜你喜欢
        • 2010-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-30
        • 2014-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多