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下一篇: Yeah.. I know.. I'm a simpleton.. So what's a Singleton?