繁体   English   中英

代码会产生竞争条件吗?

[英]Will code produce a race condition?

我有一个带有所有资源基本路径的文件。 例如:

build/scripts/script1.js  
build/scripts/script2.js

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

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

我希望做的是在启动时使用路径将文件加载到全局字典中。 该字典仅需加载一次。 不幸的是,据我所知,基本路径直到第一个请求才可用。 所以在asp.net中,我必须使用application_beginrequest而不是application_start 不好的是,现在我必须处理多线程问题。

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

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

当我只真正需要加载一次时,将为每个请求调用此方法。 我当然不喜欢这样。 由于性能原因,我不想锁定每个请求。 与大学讨论后,我们提出了一种解决方案:

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

因此,使用该解决方案,我不需要在每个请求上都进行锁定,但是如果多个线程最终在启动时获得了本节的内容,那么我将通过再次检查该对象是否在该锁内来保护它,从而对其进行保护。 这段代码会起作用吗,还是我会遇到竞争状况?

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

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

  1. 阅读字典时您错过了结果,或更糟糕的是
  2. 除非您使用ConcurrentDictionary (它还带有性能影响),否则您可能会同时对字典进行读写操作,并导致死锁(是的,众所周知, Dictionary类会在许多代码中导致死锁)。

LoadDictionary()末尾将bool _dictionaryLoaded标志(仔细检查)翻转为true可能更好。

或者,如果您在.NET 4上,请使用Lazy <> 。它更加LoadDictionary ,您所要做的就是将LoadDictionary传递为init函数。

编辑:Lazy <>在内部使用双重检查后的lock实现

暂无
暂无

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

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