代码会产生竞争条件吗?

时间:2016-07-12 18:45:11

标签: c# .net multithreading race-condition

我有一个文件,其中包含我所有资源的基本路径。例如:

https://example.org/SuperDuperSite/build/scripts/script1.js

我当然需要一个基本路径,例如:

application_beginrequest

我希望做的是在启动时使用路径将文件加载到全局字典中。字典只需要加载一次。不幸的是,据我所知,基本路径在第一次请求之前是不可用的。所以在asp.net中我必须使用application_start而不是 lock(_lock) { if (_dictionary == null) { LoadDictionary(); } } 。现在我不得不处理多线程问题。

迫使我编写以下类型的代码:

if (_dictionary == null)
{
   lock(_lock) {
      if (_dictionary == null) {
         LoadDictionary();
      }
    }
}

当我只需要加载一次时,会为每个请求调用此方法。当然,我真的不喜欢这样。出于性能原因,我不想锁定每一个请求。在与我们提出的大学交谈之后,有一个解决方案:

static String encryptionKey = "0123456789123456";

因此,使用此解决方案,我不需要锁定每个请求,但如果多个线程最终在启动时获取此部分,我将通过检查该对象是否在锁内再次为空来保护它。这段代码会起作用还是我会遇到竞争条件?

1 个答案:

答案 0 :(得分:1)

使用双重检查锁时要小心。

是的,它是线程安全的,但在您的特定代码中,您可能遇到一个微妙的错误,其中_dictionary已被实例化另一个线程(通过null检查),但尚未完全填充,您最终可能会尝试访问部分填充的字典。最后得到这两个中的一个:

  1. 您在阅读字典时遗漏了结果,或者更糟糕
  2. 除非您使用ConcurrentDictionary(这也会影响其性能),否则您可能会同时读写字典并导致死锁(是的,Dictionary已知class会在许多代码中导致死锁。)
  3. bool _dictionaryLoaded结尾处翻转到true的{​​{1}}标记(经过双重检查)可能更好。

    如果您使用的是.NET 4,请使用Lazy<>。它更清晰,您只需传入LoadDictionary()作为初始化函数即可。

    编辑:懒惰&lt;&gt;是internally implemented with a double-checked lock