C ++ 11中的双重锁定模式?

时间:2011-05-15 13:38:08

标签: multithreading c++11 singleton double-checked-locking

C ++ 11的新机器模型允许多处理器系统可靠地工作。重组指示。

正如 Meyers和Alexandrescu 指出“简单”双重检查锁定模式实现在C ++ 03中并不安全

Singleton* Singleton::instance() {
  if (pInstance == 0) { // 1st test
    Lock lock;
    if (pInstance == 0) { // 2nd test
      pInstance = new Singleton;
    }
  }
  return pInstance;
}

他们在their article中表明,无论你作为程序员做什么,在C ++ 03中,编译器都有太多的自由:允许以一种你可以不能重新排列指令的方式确保您最终只使用Singleton的一个实例。

我现在的问题是:

  • 新C ++ 11机器模型的限制/定义现在是否限制了指令序列,上述代码将始终与C ++ 11编译器一起使用?
  • 当使用新的库设施(而不是这里的模拟Lock)时,现在看起来这个Singleton模式的安全C ++ 11实现是什么样的?

3 个答案:

答案 0 :(得分:5)

如果pInstance是常规指针,则代码具有潜在的数据竞争 - 指针上的操作(或任何内置类型,就此而言)不能保证是原子(编辑:或者很好) -ordered)

如果pInstancestd::atomic<Singleton*> 并且 Lock在内部使用std::mutex来实现同步(例如,如果Lock实际上是std::lock_guard<std::mutex>),代码应该是数据竞争免费。

请注意,您需要 显式锁定和原子pInstance才能实现正确的同步。

答案 1 :(得分:4)

由于静态变量初始化现在保证是线程安全的,因此Meyer的单例应该是线程安全的。

Singleton* Singleton::instance() {
  static Singleton _instance;
  return &_instance;
}

现在您需要解决主要问题:代码中有一个Singleton。

编辑:基于我在下面的评论:与其他实施相比,此实施有一个主要缺点。如果编译器不支持此功能会发生什么?编译器将发出线程不安全的代码,甚至不发出警告。如果编译器不支持新接口,那么带锁的其他解决方案甚至都不会编译。这可能是不依赖此功能的一个很好的理由,即使是单身人士以外的其他事情。

答案 2 :(得分:1)

C ++ 11不会改变双重检查锁定实现的含义。如果你想进行双重检查锁定工作,你需要建立适当的内存屏障/栅栏。