C++ 11中的局部静态变量初始化是否是线程安全的?

Ral*_*ang 198 c++ thread-safety c++11

我知道这是一个经常被问到的问题,但由于有很多变种,我想重新陈述它,并希望有一个反映当前状态的答案.就像是

Logger& g_logger() {
    static Logger lg;
    return lg;
}
Run Code Online (Sandbox Code Playgroud)

变量lg的构造函数是否保证只运行一次?

我从以前的答案中知道,在C++ 03中,这不是; 在C++ 0x草案中,这是强制执行的.但我想要一个更明确的答案

  1. 在C++ 11标准(非草稿)中,线程安全的初始化行为是否已完成?
  2. 如果以上是肯定的,那么在当前最新版本的热门编译器中,即gcc 4.7,vc 2011和clang 3.0,它们是否正确实施?

Ker*_* SB 176

有关第6.7节:

第一次控制通过其声明时初始化这样的变量; 这样的变量在初始化完成后被认为是初始化的.[...]如果控件在初始化变量时同时进入声明,则并发执行应等待初始化完成.

然后有一个脚注:

实现不得在执行初始化程序时引入任何死锁.

所以,是的,你很安全.

(这当然没有说明通过引用随后访问变量.)

  • @Nawaz:嗯,这是真的,但这也是一个完整的普遍性:共享数据的并发访问必须同步.我不认为有任何暗示静态初始化会以某种方式提供该规则的豁免,因此我认为不值得特别提出. (35认同)
  • 值得注意的是,`static Logger lg;`只有在`Logger`的默认构造函数是线程安全的时才是线程安全的,即它不会在内部访问任何可修改的共享资源,比如通过全局变量或单例.应该注意的是,标准保证*only*this:如果更多的一个线程尝试同时开始执行构造函数,则只有其中一个*实际*执行它,其余的将等待初始化完成.但是,标准不保证构造函数本身的线程安全性. (28认同)
  • @Nawaz:构造函数必须是线程安全的吗?你自己说只有一个线程会执行构造函数. (9认同)
  • @KerrekSB:我也解释了我的意思:*即它不会在内部*访问任何**可修改的共享资源**.仅仅因为只有一个线程执行构造函数,并不一定意味着它所做的是线程安全的.如果它修改了不受保护的共享资源,那么它就不是线程安全的. (6认同)
  • 这对`static Logger *lg = new Logger();` 是否也有效? (4认同)

Den*_*tov 15

--fno-threadsafe-statics也值得一提.在gcc中:

不要发出额外的代码来使用C++ ABI中指定的例程来进行本地静态的线程安全初始化.您可以使用此选项在不需要线程安全的代码中略微减小代码大小.

另外,看一下旧线程Are函数静态变量是否在GCC中是线程安全的?