不检查静态字典线程安全中的键是否存在? Resharper认为不是

Is not checking key existence in a static dictionary thread-safe? Resharper thinks it's not

Resharper 建议将 return dic.Contains("v1"); 包装在 lock 语句中说“该字段有时在同步块内使用,有时在没有同步的情况下使用":

public class MyClass
{
    private static Dictionary<string, string> _dic = new Dictionary<string, string>();

    protected bool V1Exist()
    {
        return dic.Contains("v1");            
    }
}

但是我不明白为什么示例中需要 lock。对我来说它看起来很安全。请指教

众所周知,字典不是线程安全的,因此您应该同步写入和读取。但是,如果您想了解可能出错的具体示例 - 考虑这个小应用程序:

static void Main(string[] args) {
    var dict = new Dictionary<int, int>();
    dict.Add(0, 0);
    new Thread(() => {
        for (int i = 1; i < int.MaxValue; i++) {
            lock (dict) {
                dict.Add(i, i);
                dict.Remove(i);
            }
        }
    }).Start();
    new Thread(() => {
        while (true) {
            if (!dict.ContainsKey(0))
                throw new Exception("cannot happen?");
        }
    }).Start();
    Console.ReadKey();
}

我们创建了一个字典,其中包含一个带有键 0 的条目,然后我们 运行 两个线程。第一个线程不断地向字典添加和删除键,但请注意它不会删除键为 0 的项目。键为 0 的项目始终存在。

第二个线程不断检查是否有键为 0 的项目,如果没有则抛出异常。您可能认为这永远不会发生,因为我们永远不会删除键为 0 的项目,但事实并非如此。如果您 运行 这个应用程序,它几乎会立即抛出 "cannot happen?" 异常。如果你在 ContainsKey 附近加锁——这永远不会发生。

所以简而言之,如果您没有正确地同步对非线程安全结构的访问,甚至是读取,事情可能会变得非常糟糕。您甚至可能没有注意到这一点,并且很难调试此类问题,因为应用程序可能表现得一切正常。