字典"ContainsKey"上的双重检查锁定

Jar*_*rrr 15 c# collections multithreading dictionary double-checked-locking

我的团队目前正在讨论这个问题.

有问题的代码就是这样的

if (!myDictionary.ContainsKey(key))
{
    lock (_SyncObject)
    {
        if (!myDictionary.ContainsKey(key))
        {
            myDictionary.Add(key,value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我见过的一些帖子说这可能是一个很大的NO NO(当使用TryGetValue时).然而,我们团队的成员说没关系,因为"ContainsKey"不会对密钥集合进行迭代,而是通过O(1)中的哈希代码检查密钥是否包含在内.因此他们声称这里没有危险.

我想就此问题得到您的诚实意见.

Jon*_*eet 27

不要这样做.这不安全.

你可以ContainsKey在另一个线程调用时从一个线程调用Add.这根本就不受支持Dictionary<TKey, TValue>.如果Add需要重新分配存储桶等,我可以想象你可能得到一些非常奇怪的结果,或者例外.它可能是以你没有看到任何令人讨厌的效果的方式编写的,但我不想依赖它.

它是利用一件事双重检查锁定为简单的读/写操作的领域,虽然我还是反对它-它的另一个做出已经明确地描述为一个API调用不被用于多个并发呼叫的安全.

如果您使用的是.NET 4,那么ConcurrentDictionary可能就是前进的方向.否则,只需锁定每次访问.

  • @Amir:是的.您可以使用`ReaderWriterLockSlim`来允许并发读者,但我只是先尝试​​锁定*every*access,然后对应用程序进行概要分析以确定它是否有问题. (2认同)

Col*_*kay 6

如果您处于多线程环境中,您可能更愿意使用ConcurrentDictionary.几个月前我在博客上发表了这篇文章,你可能会发现这篇文章很有用:http://colinmackay.co.uk/blog/2011/03/24/parallelisation-in-net-4-0-the-concurrent-dictionary /


Jar*_*Par 6

此代码不正确.该Dictionary<TKey, TValue>类型不支持同时读写操作.即使你的Add方法是在锁内调用的ContainsKey,也不是.因此,它很容易导致违反同时读/写规则,并会导致实例中的损坏