c++ - 在 C++ 中使用带内存屏障的双重检查锁定的正确方法是什么?

标签 c++ singleton double-checked-locking

我刚刚阅读了优秀的博客 C++ and the Perils of Double-Checked Locking

而且我不明白为什么我们必须使用示例 12 中的第一个内存屏障(如下所示):

Singleton* Singleton::instance () {
       Singleton* tmp = pInstance;
       ... // insert memory barrier
       if (tmp == 0) {
          Lock lock;
          tmp = pInstance;
          if (tmp == 0) {
             tmp = new Singleton;
             ... // insert memory barrier
             pInstance = tmp;
          }
       }
       return tmp;
    }

将其更改为以下代码是否安全?为什么不呢?

Singleton* Singleton::instance () {
       if (pInstance == 0) {
          Lock lock;
          if (pInstance == 0) {
             Singleton* tmp = new Singleton;
             ... // insert memory barrier
             pInstance = tmp;
          }
       }
       return pInstance;
    }

最佳答案

不,这不安全。阅读示例前的三段和示例后的两段,潜在的问题是在构建 Singleton 之前在线程 B 上完成对 pInstance 的写入(刷新到内存)的系统 已被刷新。然后线程 A 可以读取 pInstance,将指针视为非 null,并返回它可能允许线程 A 在线程 B 完成将其存储到内存之前访问 Singleton

第一次刷新是必要的,以确保Singleton 构造期间写入的刷新已完成您尝试在不同的线程中使用它。 p>

根据您运行的硬件,这可能不是问题。

关于c++ - 在 C++ 中使用带内存屏障的双重检查锁定的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52981057/

相关文章:

c++ - 大括号中发生了什么

ruby - Ruby 中的单例模式与单态模式

java - Java可以在通过某种方法构造对象之前写入对对象的引用吗?

java - 为什么要仔细检查单例实例化

c++ - 模板参数推导如何区分左值和文字/编译时值

c++ - 第二次运行tshark.c源文件后的 fatal error

go - 如何创建单例数据库实例

c# - 再次仔细检查锁定和 C#

c++ - 在调用它之前如何定义这个函数?

objective-c - 为什么给单例的静态变量赋了一个nil