具有易失性或记忆障碍的双重锁定

Fra*_* Q. 4 .net c# multithreading volatile memory-barriers

这是我的代码,运行几个月没有任何问题.

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;
        }
    }      
}
Run Code Online (Sandbox Code Playgroud)

但是,我遇到了这个链接,并概述了上述问题.

a)写入Singleton.value = new Singleton();可能会缓存在处理器上,因此其他线程可能不会最终看到它.要volatile使用,请使用此关键字.

问(1):C#lock关键字不能解决这个问题吗?

b)在同一篇文章中概述的另一个更好的解决方案是在写入之后避免volatile和引入.System.Threading.Thread.MemoryBarrier();Singleton.value

问题:

问(2)我不太明白MemoryBarrier()写完后的必要性.什么可能的重新排序可能会导致其他线程看到Singleton.valuenull?在lock阻止其他线程甚至读什么.

Q(3)障碍只会维持秩序,但如果仍然从某些缓存中读取该值,该怎么办呢?是不是仍然需要挥发性?

Q(4)因为C#lock本身就是它所需要的屏障吗?

最后,我是否需要使用任何一种方法更新我的代码或者它是否足够好?

编辑 有一个答案建议使用Lazy初始化.我知道了.

但他们试图使用volatie和memorybarrier来实现锁定并不能保证什么?

Eri*_*ert 9

这是我的代码,运行几个月没有任何问题.

如果有一个十亿分之一的失败机会,并且代码在一千台机器上每天运行一千次,那么平均每三年就有一次不可能调试的关键故障.

如果它只在特定硬件上失败,并且您在x86上进行了所有测试,那么您将永远不会看到失败.

没有测试低锁代码的正确性的事情.代码可以证明是正确的,或者不是.你不能依赖测试.

C#lock关键字不能解决这个问题吗?

在其中一个读数上省略了锁定.

锁可以防止其他线程甚至读取任何内容.

在其中一个读数上省略了锁定.

障碍只会维持秩序,但如果仍然从某些缓存中读取值,该怎么办呢.是不是仍然需要挥发性?

从缓存中读取相当于及时向后移动读取; 由挥发性或显性障碍引起的障碍限制了如何观察这种向后运动.

是否真的需要屏障,因为C#锁定自己放置它?

在其中一个读数上省略了锁定.

我是否需要使用任何一种方法更新我的代码,还是足够好?

我永远不会写这样的代码.如果您需要延迟初始化,请使用Lazy<T>.如果需要单例,请使用单例模式的标准实现.不要自己解决这些问题; 让专家为您解决这些问题.

但他们试图使用volatile和memorybarrier来实现锁定并不能保证什么?

他们试图正确地忽略锁定,从而在非竞争路径中节省几纳秒.与难以调试的罕见关键故障的成本相比,这些纳秒对您的用户有多大价值?

每当你试图忽略锁定时,你就完全沉浸在低级记忆模型的疯狂世界中.你必须假设所有的记忆都在不断变化,除非有什么东西保持不变; 您必须假设存储器访问的任何和所有合法重新排序都是可能的,即使在大多数硬件上也是不可能的.您不知道将来会发明什么奇怪的硬件并用于运行您的代码.

不要去那里.我不喜欢使用线程; 如果我想并行化某些东西,我的偏好是在问题上抛出虚拟机,容器或进程.如果必须使用线程,请尝试不共享内存.如果你有共享存储,使用由专家建立的最高级别的结构,像TaskLazy,而不是滚动您自己出的记忆障碍和联锁操作.

  • @acelent:如果有人在数学上说"你的P = NP的'证据'甚至没有开始解决专家们已知的几十年的证据中的二十几个问题;不要去那里,这是浪费你的时间和每个人的时间你都会打扰你的曲柄样板",那么我会把它视为公共服务.我在这里提供扎实,实用的工程建议.**我们作为语言设计师失败了**.我们已经构建了太复杂而无法正确使用的系统,并且未能提倡更简单,更安全的系统.我试图以尽可能小的方式缓解这种情况. (3认同)
  • "我不喜欢使用线程" - 无价!大多数问题都没有以这种方式解决.如果您的问题无法在1'线程'上解决,那么`x`'线程'不会因任何因素而改善它. (2认同)