c# - 线程安全单例 : why the memory model does not guarantee that the new instance will be seen by other threads?

标签 c# multithreading

我在 Jon 的 Skeet 在线页面上阅读了有关如何在 C# 中创建线程安全的单例

http://csharpindepth.com/Articles/General/Singleton.aspx

// Bad code! Do not use!
public sealed class Singleton
{
    private static Singleton instance=null;

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

在这段代码下面的段落中,它说:

As hinted at before, the above is not thread-safe. Two different threads could both have evaluated the test if (instance==null) and found it to be true, then both create instances, which violates the singleton pattern. Note that in fact the instance may already have been created before the expression is evaluated, but the memory model doesn't guarantee that the new value of instance will be seen by other threads unless suitable memory barriers have been passed.

您能解释一下为什么内存模型不能保证实例的新值会被其他线程看到吗?

静态变量位于堆上,但为什么不立即与其他线程共享?我们是否需要等待上下文切换,以便其他线程知道实例不再为空?

最佳答案

Can you please explain why doesn't the memory model does not guarantee that the new value of instance will be seen by other threads?

内存模型很复杂,目前还没有非常清楚地记录下来,但从根本上说,很少有情况可以安全地依赖一个线程写入的值在另一个线程上“看到”而没有一些锁定或其他正在进行线程间通信。

例如,考虑一下:

// Bad code, do not use
public class BigLoop
{
    private static bool keepRunning = true;

    public void TightLoop()
    {
        while (keepRunning)
        {
        }
    }

    public void Stop()
    {
        keepRunning = false;
    }
}

如果您创建了两个线程,其中一个调用 TightLoop,另一个调用 Stop,则无法保证循环方法永远 终止。

现代 CPU 中有很多级别的缓存,要求每次读取都返回到主内存会消除很多优化。所以我们有内存模型来保证在什么情况下哪些变化肯定是可见的。除了这些保证之外,JIT 编译器还可以假设实际上只有一个线程 - 例如,它可以将字段的值缓存在寄存器中,并且再也不会访问主内存。

当前记录的内存模型严重不足,建议一些明显奇怪的优化应该是有效的。我不会沿着这条路走得太远,但值得阅读 Joe Duffy 在 CLR 2.0 memory model 上的博客文章. (这比文档化的 ECMA 内存模型更强大,但博客文章并不是此类关键文档的理想位置,我认为仍然需要更加清晰。)

The static variable is located on the heap, but why it is not shared with other threads?

与其他线程共享 - 但该值不一定立即可见。

关于c# - 线程安全单例 : why the memory model does not guarantee that the new instance will be seen by other threads?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47816720/

相关文章:

c - 调用 swapcontext() 后队列丢失指针

c# - 为什么我可以锁定 C# 中的任何对象类型?

c - 当 `func`结束时线程会自动退出吗?

multithreading - 从另一个线程调用 FnMut 回调

c# - 如何将图像与线条合并并将两者保存在文件中?

c# - 发布我的第一个应用程序 -> 权限被拒绝

c# - LINQ 在 XML 文件中创建新记录

c# - 使用类型实例化使用受限泛型的派生类

c# - WPF 通过网格本身向 DataGrid 添加行

c++ - 定期检查条件而不阻塞