use*_*715 67 c++ singleton pthreads thread-safety
单身类的通常模式就像
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
inst = new Foo(...);
return *inst;
}
Run Code Online (Sandbox Code Playgroud)
但是,我的理解是这个解决方案不是线程安全的,因为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;
}
Run Code Online (Sandbox Code Playgroud)
这是正确的做法,还是我应该注意哪些陷阱?例如,是否存在可能发生的静态初始化顺序问题,即在第一次调用getInst时,inst总是保证为NULL?
Sat*_*Sat 84
如果您使用的是C++ 11,这是一种正确的方法:
Foo& getInst()
{
static Foo inst(...);
return inst;
}
Run Code Online (Sandbox Code Playgroud)
根据新标准,不再需要关心这个问题.对象初始化只能由一个线程完成,其他线程将等待它完成.或者你可以使用std :: call_once.(更多信息在这里)
Joe*_*oeG 42
您的解决方案称为"双重检查锁定",您编写它的方式不是线程安全的.
这篇Meyers/Alexandrescu论文解释了为什么 - 但这篇论文也被广泛误解.它开始了'双重检查锁定在C++中的不安全'模因 - 但它的实际结论是C++中的双重检查锁定可以安全地实现,它只需要在非显而易见的地方使用内存屏障.
本文包含伪代码,演示如何使用内存屏障来安全地实现DLCP,因此您应该不难纠正您的实现.
qqi*_*row 11
Herb Sutter谈到了CppCon 2014中的双重锁定.
下面是我在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;
}
Run Code Online (Sandbox Code Playgroud)
您也可以在这里查看完整的程序:http://ideone.com/olvK13