gpt4 book ai didi

c# - 如何证明 Dictionary 的 TryGetValue 的双重检查锁定模式不是线程安全的

转载 作者:可可西里 更新时间:2023-11-01 08:00:31 24 4
gpt4 key购买 nike

最近我看到一些 C# 项目在 Dictionary 上使用双重检查锁定模式。像这样:

private static readonly object _lock = new object();
private static volatile IDictionary<string, object> _cache =
new Dictionary<string, object>();

public static object Create(string key)
{
object val;
if (!_cache.TryGetValue(key, out val))
{
lock (_lock)
{
if (!_cache.TryGetValue(key, out val))
{
val = new object(); // factory construction based on key here.
_cache.Add(key, val);
}
}
}
return val;
}

此代码不正确,因为 Dictionary 可以在 _cache.Add() 中“增长”集合,而 _cache.TryGetValue (锁外)正在遍历集合。在许多情况下这可能极不可能,但仍然是错误的。

是否有一个简单的程序可以证明这段代码失败了?

将其合并到单元测试中是否有意义?如果是这样,怎么做到的?

最佳答案

显然代码不是线程安全的。我们这里有一个明显的例子,说明过早优化的危害。

请记住,双重检查锁定模式的目的是通过消除锁定成本来提高代码性能。如果锁是无争议的,它已经非常便宜了。因此,只有在以下情况下,双重检查锁定模式才是合理的:(1) 锁将被激烈竞争,或 (2) 代码对性能如此难以置信敏感以至于成本未竞争的锁仍然太高。

显然我们不是第二种情况。看在上帝的份上,你正在使用字典。即使没有锁,它也会进行查找和比较,这比避免无竞争锁节省的成本要高出数百或数千倍。

如果我们处于第一种情况,那么找出导致争用的原因并消除它。如果你在一个锁上做了很多等待,那么弄清楚为什么会这样,并用一个细长的读写锁替换锁定,或者重组应用程序,这样就不会有那么多线程同时敲打同一个锁时间。

无论哪种情况,都没有理由采用危险的、对实现敏感的低锁技术。您应该只在极少数情况下使用低锁技术,在这些情况下您真的、真的无法承受无竞争锁的成本。

关于c# - 如何证明 Dictionary 的 TryGetValue 的双重检查锁定模式不是线程安全的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2624301/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com