【发布时间】:2018-02-28 17:20:46
【问题描述】:
这是我已有的代码,运行了几个月没有任何问题。
public sealed class Singleton
{
private static Singleton value;
private static object syncRoot = new Object();
public static Singleton Value
{
get
{
if (Singleton.value == null)
{
lock (syncRoot)
{
if (Singleton.value == null)
{
Singleton.value = new Singleton();
}
}
}
return Singleton.value;
}
}
}
但是,我遇到了这个link,它概述了上述问题。
a) 写入Singleton.value = new Singleton(); 可能会缓存在处理器上,因此其他线程可能最终看不到它。使用volatile 关键字修复此问题。
Q(1):C# lock 关键字不处理这个问题吗?
b) 在同一篇文章中概述的另一个更好的解决方案是避免volatile,并在写入Singleton.value 之后引入System.Threading.Thread.MemoryBarrier();。
问题:
Q(2) 写完后我不太明白MemoryBarrier() 的必要性。什么可能的重新排序可能会导致其他线程将 Singleton.value 视为 null ? lock 阻止其他线程甚至读取任何内容。
Q(3) 屏障只会维持顺序,但如果仍然从某个缓存中读取值怎么办。 volatile 还不需要吗?
Q(4) 既然 C# lock 自己放置了屏障,那里真的需要屏障吗?
最后, 我需要用这两种方法更新我的代码还是足够好?
修改
有一个答案建议使用Lazy 初始化。我得到了它。
但是他们试图使用锁不能保证的 volatie 和 memorybarrier 来完成什么?
【问题讨论】:
-
我什至不确定您要问什么。你只是想实现一个单例吗?
-
一些 Microsoft 员工将永远无法完全从处理安腾处理器中恢复过来。不幸的是,他们用 volatile 来驯服野兽的废话也出现在 C# 规范中。今天一切都无关紧要。使用 Lazy 类。
-
@FrankQ。 “执行当前线程的处理器不能以这样一种方式重新排序指令,即调用 MemoryBarrier 之前的内存访问在调用 MemoryBarrier 之后的内存访问之后执行。”因此,如果没有 MemoryBarrier,安腾处理器将重新排序指令。
-
链接的 MSDN 文章存在根本缺陷。单独的内存屏障是无用的——你需要另一个屏障来读取。
标签: c# .net multithreading volatile memory-barriers