我知道以下是在C ++ 11中实现单例的一种线程安全的方法:
Foo* getInst()
{
static Foo* inst = new Foo(...);
return inst;
}
我在this answer中读到以下内容也是线程安全的:
Foo& getInst()
{
static Foo inst(...);
return inst;
}
它真的是线程安全的吗?
问题是Foo 的实例将在单个堆栈框架中分配不会在堆上分配吗?
如果它是线程安全的,是否有充分理由选择其中一个?
答案 0 :(得分:9)
静态变量在堆栈上分配 NOT 。在第一个变体中,您有一个静态指针(一个全局变量),它是用从堆中获取的内存初始化的,而在第二个变种中,您有一个完整的静态对象。
两个版本都使用内部编译器保护(即__cxa_guard_acquire()
和__cxa_guard_release()
,它们在功能上等同于mutex::lock()
和mutex::unlock()
),以确保对特定变量的序列化访问您的全局实例是否已初始化。
您的代码:
Foo& getInst()
{
static Foo inst(...);
return inst;
}
编译后实际上看起来像那样:
Foo& getInst()
{
static Foo inst; // uninitialized - zero
static guard instGuard; // zero
if (is_initialized(instGuard) == false)
{
__cxa_guard_acquire(instGuard);
// do the initialization here - calls Foo constructor
set_initialized(instGuard);
__cxa_guard_release(instGuard);
}
return inst;
}
所以你的两个例子都是线程安全的。
答案 1 :(得分:4)
inst
不会在堆栈上分配。它将分配到.data
或.bss
部分的某个位置。否则,这个静态变量在程序执行的所有时间都不能生存,所以每次进入这个函数时,它都不能具有相同的值。