繁体   English   中英

字典“ContainsKey”上的双重检查锁定

[英]Double checked locking on Dictionary “ContainsKey”

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

有问题的代码就是这样的

if (!myDictionary.ContainsKey(key))
{
    lock (_SyncObject)
    {
        if (!myDictionary.ContainsKey(key))
        {
            myDictionary.Add(key,value);
        }
    }
}

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

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

不要这样做。 这不安全。

您可以从一个线程调用ContainsKey ,而另一个线程调用Add 这完全不受Dictionary<TKey, TValue> 如果Add需要重新分配存储桶等,我可以想象你可能得到一些非常奇怪的结果或异常。 可能是以你没有看到任何令人讨厌的效果的方式编写的,但我不想依赖它。

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

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

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

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

它看起来不是线程安全的,但可能很难让它失败。

迭代与散列查找参数不成立,例如可能存在哈希冲突。

如果这个字典很少被编写并且经常被读取,那么我经常通过在写入时替换整个字典来使用安全双锁。 如果您可以批量写入以减少它们的频率,则此功能尤其有效。

例如,这是我们使用的方法的简化版本,它试图获取与类型相关联的模式对象,如果不能,则继续并为其在同一类型中找到的所有类型创建模式对象。程序集作为指定的类型,以最小化整个字典必须复制的次数:

    public static Schema GetSchema(Type type)
    {
        if (_schemaLookup.TryGetValue(type, out Schema schema))
            return schema;

        lock (_syncRoot) {
            if (_schemaLookup.TryGetValue(type, out schema))
                return schema;

            var newLookup = new Dictionary<Type, Schema>(_schemaLookup);

            foreach (var t in type.Assembly.GetTypes()) {
                var newSchema = new Schema(t);
                newLookup.Add(t, newSchema);
            }

            _schemaLookup = newLookup;

            return _schemaLookup[type];
        }
    }

因此,在这种情况下,字典最多将被重建,因为有类型需要模式的程序集。 对于应用程序生命周期的其余部分,字典访问将是无锁的。 字典副本成为程序集的一次性初始化成本。 字典交换是线程安全的,因为指针写入是原子的,因此整个引用立即被切换。

您也可以在其他情况下应用类似的原则。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM