高效的线程安全单例在C ++中

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

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

然而,我的理解是这个解决scheme不是线程安全的,因为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; } 

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

你的解决scheme被称为“双重检查locking”,你写的方式不是线程安全的。

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

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

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

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

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

使用pthread_once ,这是保证初始化函数运行一次primefaces。

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

Herb Sutter谈到CppCon 2014的双重locking。

下面是我在C ++ 11基础上实现的代码:

 class Foo { public: static Foo* Instance(); private: Foo() {} static atomic<Foo*> pinstance; static mutex m_; }; atomic<Foo*> Foo::pinstance { nullptr }; std::mutex Foo::m_; Foo* Foo::Instance() { if(pinstance == nullptr) { lock_guard<mutex> lock(m_); if(pinstance == nullptr) { pinstance = new Foo(); } } return pinstance; } 

您也可以在这里查看完整的程序: http : //ideone.com/olvK13

TTBOMK,唯一保证线程安全的方式来做到这一点,而不是locking将是您启动线程之前初始化所有的单身人士。

您的替代品被称为“双重检查locking” 。

可能存在multithreading内存模型,但POSIX并不能保证它

ACE单例实现使用双重检查locking模式进行线程安全,如果您愿意,可以参考它。

你可以在这里find源代码。