C ++中的安全单例

单身类的通常模式是类似的

static Foo &getInst()
{
  static Foo *inst = NULL;
  if(inst == NULL)
    inst = new Foo(...);
  return *inst;    
}

然而,我的理解是这个解决方案不是线程安全的,因为1)Foo的构造函数可能会被多次调用(这可能会也可能不重要),2)在返回到不同线程之前,inst可能不会被完全构造。

一种解决方法是在整个方法中包装一个互斥锁,但是在我真正需要它之后,我花了很长时间同步开销。 另一种是类似的

static Foo &getInst()
{
  static Foo *inst = NULL;
  if(inst == NULL)
  {
    pthread_mutex_lock(&mutex);
    if(inst == NULL)
      inst = new Foo(...);
    pthread_mutex_unlock(&mutex);
  }
  return *inst;    
}

这是做这件事的正确方法,还是我应该知道的任何陷阱? 例如,是否有任何可能发生的静态初始化顺序问题,即在第一次调用getInst时,inst始终保证为NULL?


您的解决方案称为“双重检查锁定”,并且您写入的方式不是线程安全的。

这份Meyers / Alexandrescu的文章解释了为什么 - 但该文件也被广泛误解。 它启动了'双重检查锁定在C ++中不安全' - 但它的实际结论是C ++中的双重检查锁定可以安全地实现,它只需要在非显而易见的地方使用内存障碍。

该论文包含的伪代码演示了如何使用内存屏障来安全地实现DLCP,因此您应该不难纠正您的实现。


如果你使用C ++ 11,这是一个正确的方法来做到这一点:

Foo& getInst()
{
    static Foo inst(...);
    return inst;
}

根据新标准,再也不需要关心这个问题了。 对象初始化将仅由一个线程完成,其他线程将一直等待完成。 或者你可以使用std :: call_once。 (更多信息在这里)


使用pthread_once ,这可以保证初始化函数以原子方式运行一次。

(在Mac OS X上,它使用自旋锁,不知道其他平台的实现情况。)

链接地址: http://www.djcxy.com/p/50085.html

上一篇: safe singleton in C++

下一篇: Yeah.. I know.. I'm a simpleton.. So what's a Singleton?