我知道gcc和llvm-clang发出代码以线程安全的方式初始化本地静态变量(这允许通过在函数中包装全局静态来逃避静态顺序初始化失败)。
然而,This msdn blog post是我在这些情况下可以找到的关于vcc行为的最佳文档,并且声称静态初始化不能是线程安全的,因为本地静态的初始化可以递归地调用相同的作用域。
我不买这个论点 - 如果初始化者依赖于自己的结果,这显然是编程错误。
因此,鉴于本文来自2004年,gcc和clang可以做到这一点,并且the current msvc documentation是不明确的(声明'分配'到本地静态不是线程安全的,但仅此而已):
在MSVC中,本地静态的初始化现在是线程安全的吗?
如果没有,为什么不呢,因为gcc显然可以这样做,但程序员很难在之后添加。
答案 0 :(得分:1)
我听说它已经在vs2010中实现了,但找不到任何引用。无论如何,在c ++ 0x标准中,这样的初始化明确要求是线程安全的,所以迟早ms会遵守我的猜测。
答案 1 :(得分:1)
C ++ 0x标准说:
§6.7声明声明[stmt.dcl]
4 / 具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的所有块范围变量的零初始化(8.5)在执行任何其他初始化之前执行地点。具有静态存储持续时间的块范围实体的常量初始化(3.6.2)(如果适用)在首次输入块之前执行。 允许实现在静态或线程存储持续时间内执行其他块范围变量的早期初始化,条件是允许实现在命名空间范围内静态初始化具有静态或线程存储持续时间的变量(3.6.2)。否则,在第一次控制通过其声明时初始化这样的变量;这样的变量在初始化完成后被认为是初始化的。
如果初始化通过抛出异常退出,则初始化未完成,因此下次控件进入声明时将再次尝试。
如果控件在初始化变量时同时进入声明,则并发执行应等待初始化完成。 88
如果控件在初始化变量时以递归方式重新输入声明,则行为未定义。
[例如:
int foo(int i) {
static int s = foo(2*i); // recursive call - undefined
return i+1;
}
-end example]
88)实现不得在执行初始化程序时引入任何死锁。
正如所料,它已经相当完整。
然而事实是即使旧版本的gcc已经遵守了这一点,事实上甚至做得更好:在递归初始化的情况下,会抛出异常。
最后,关于程序员之后添加它:如果你有比较和交换可用的东西,你通常可以这样做,并使用一个足够小的变量,依靠变量的零初始化来标记其非计算状态。但是我确实同意,如果它被烘焙的话要容易得多。
恐怕我已经停止了VC ++的进展,所以我不知道它现在在哪里。我唯一的建议是......在装配级别查找。