代码会产生竞争条件吗?
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();
}
}
}
因此,使用此解决方案,我不需要锁定每个请求,但如果多个线程在启动时最终获得此部分,我将通过检查锁内的对象是否再次为 null 来保护它。这段代码会起作用还是我会 运行 进入竞争状态?
使用双重检查锁时要小心。
是的,它是线程安全的,但是在您的特定代码中,您可能运行陷入一个微妙的错误,其中_dictionary
已经 实例化 由另一个线程(通过 null
检查),但尚未完全 填充 ,您可能最终会尝试访问部分填充的字典.最后得到这两个之一:
- 您在阅读字典时遗漏了结果,或者更糟
- 除非你使用
ConcurrentDictionary
(这也会带来性能影响),否则你可能会同时读取和写入字典,并导致死锁(是的,Dictionary
class 已知会在许多代码中导致死锁。
bool _dictionaryLoaded
标志(双重检查),在 LoadDictionary()
末尾翻转为 true
可能更好。
或者如果您使用的是 .NET 4,则使用 Lazy<>。它更简洁,您所要做的就是传入 LoadDictionary
以用作初始化函数。
我有一个文件,其中包含我所有资源的基本路径。例如:
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();
}
}
}
因此,使用此解决方案,我不需要锁定每个请求,但如果多个线程在启动时最终获得此部分,我将通过检查锁内的对象是否再次为 null 来保护它。这段代码会起作用还是我会 运行 进入竞争状态?
使用双重检查锁时要小心。
是的,它是线程安全的,但是在您的特定代码中,您可能运行陷入一个微妙的错误,其中_dictionary
已经 实例化 由另一个线程(通过 null
检查),但尚未完全 填充 ,您可能最终会尝试访问部分填充的字典.最后得到这两个之一:
- 您在阅读字典时遗漏了结果,或者更糟
- 除非你使用
ConcurrentDictionary
(这也会带来性能影响),否则你可能会同时读取和写入字典,并导致死锁(是的,Dictionary
class 已知会在许多代码中导致死锁。
bool _dictionaryLoaded
标志(双重检查),在 LoadDictionary()
末尾翻转为 true
可能更好。
或者如果您使用的是 .NET 4,则使用 Lazy<>。它更简洁,您所要做的就是传入 LoadDictionary
以用作初始化函数。