C ++ 11中的线程安全单例

时间:2014-11-16 07:57:48

标签: c++ multithreading c++11 gcc thread-safety

我知道以下是在C ++ 11中实现单例的一种线程安全的方法:

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

我在this answer中读到以下内容也是线程安全的:

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

它真的是线程安全的吗? 问题是Foo 的实例将在单个堆栈框架中分配不会在堆上分配吗?

如果它是线程安全的,是否有充分理由选择其中一个?

2 个答案:

答案 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部分的某个位置。否则,这个静态变量在程序执行的所有时间都不能生存,所以每次进入这个函数时,它都不能具有相同的值。