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



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

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

我在这个答案中读到以下内容也是线程安全的:

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

它真的是线程安全的吗?
单个堆栈帧中分配的 Foo 实例不会在堆上分配,这不是一个问题吗?

如果它是线程安全的,是否有充分的理由更喜欢一个而不是另一个?

静态变量不会在堆栈上分配。在第一个变体中,你有一个静态指针(一个全局变量),用从堆获得的内存初始化,而在第二个变体中,你有整个静态对象。

这两个版本都使用内部编译器保护(即__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;
}

所以你的两个考试都是线程安全的。

示例中的inst不会在堆栈上分配。它将.data.bss部分中的某个位置分配。否则,这个静态变量不能一直存在于程序执行的时间,因此它不能具有相同的值,就像以前一样,每次你输入这个函数。

最新更新