局部静态的线程安全初始化:MSVC [重复]
Posted
技术标签:
【中文标题】局部静态的线程安全初始化:MSVC [重复]【英文标题】:Thread-safe initialisation of local statics: MSVC [duplicate] 【发布时间】:2011-09-27 10:47:48 【问题描述】:可能重复:Is static init thread-safe with VC2010?
我知道 gcc 和 llvm-clang 会发出代码以线程安全的方式初始化局部静态变量(这允许人们通过在函数中包装全局静态来逃避静态顺序初始化失败)。
然而,This msdn blog post 是我能找到的关于 vcc 在这些情况下的行为的最佳文档,并且声称静态初始化永远不可能是线程安全的,因为本地静态的初始化程序可以递归地调用相同的范围。
我不赞成这个论点 - 如果初始化程序依赖于它自己的结果,这显然是一个编程错误。
因此,鉴于这篇文章是 2004 年的,gcc 和 clang 可以做到,而 the current msvc documentation 是模棱两可的(声明“分配”给本地静态不是线程安全的,仅此而已):
本地静态的初始化现在在 MSVC 中是线程安全的吗?
如果没有,为什么不呢,因为 gcc 显然可以做到这一点,但程序员之后很难添加。
【问题讨论】:
由于 C++03 不需要此时的线程安全,因此两个编译器在执行它们的操作时都一样正确。找出答案的唯一方法是查看生成的代码。可能它甚至取决于编译器标志(当你想要单线程代码时,gcc 肯定会让你禁用使用的互斥锁) @PlasmaHH 也许,但您希望它出现在文档中 - 这是一个非常有用的功能! 至少在 gcc 手册页中是这样。不知道(也不太在意)MSVC。 【参考方案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;
——结束示例]
88) 实现不得在初始化程序的执行过程中引入任何死锁。
果然还是挺完整的。
然而事实是,即使是旧版本的 gcc 也已经遵守了这一点,而且实际上做得更好:在递归初始化的情况下,会引发异常。
最后,关于以后添加它的程序员:如果您有可用的比较和交换之类的东西,您通常可以这样做,并使用足够小的变量,依靠变量的零初始化来标记其非计算状态。不过,我确实同意,如果它被烘焙进去会容易得多。
恐怕我已经停止关注 VC++ 的进展,所以我不知道它现在的位置。我唯一的建议是……在汇编级别查找。
【讨论】:
【参考方案2】:听说vs2010已经实现了,但是找不到参考。无论如何,在 c++0x 标准中,此类初始化被明确要求是线程安全的,所以我猜迟早 ms 会遵守。
【讨论】:
vs2010 中没有实现。根据msdn.microsoft.com/en-us/library/hh567368.aspx(将这个特性称为“魔法静态”),第一个实现C++11这方面的Visual Studio版本是vs2015。以上是关于局部静态的线程安全初始化:MSVC [重复]的主要内容,如果未能解决你的问题,请参考以下文章