本地静态的线程安全初始化:MSVC
Thread-safe initialisation of local statics: MSVC
可能重复:
VC2010的静态初始化线程安全吗?
我知道gcc和llvm clang发出代码以线程安全的方式初始化局部静态变量(这允许通过在函数中封装全局静态来避免静态顺序初始化的失败(。
然而,这篇msdn博客文章是我能找到的关于vcc在这种情况下的行为的最好的文档,它声称静态初始化永远不可能是线程安全的,因为本地静态的初始化程序可以递归地调用相同的范围。
我不相信这个论点——如果初始化程序依赖于它自己的结果,这显然是一个编程错误。
因此,考虑到这篇文章来自2004年,gcc和clang可以做到这一点,并且当前的msvc文档是不明确的(声明"分配"给本地静态不是线程安全的,但仅此而已(:
本地静态的初始化现在在MSVC中是线程安全的吗
如果没有,为什么不呢,因为gcc显然可以做到这一点,但程序员很难在之后添加
C++0x标准说:
§6.7声明声明[stmt.dcl]
4/具有静态存储持续时间(3.7.1(或线程存储持续时间的所有块范围变量的零初始化(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也已经遵守了这一点,而且实际上做得更好:在递归初始化的情况下,会抛出异常。
最后,关于程序员在之后添加它:如果有Compare And Swap之类的东西可用,并且使用一个足够小的变量,依靠变量的零初始化来标记其非计算状态,那么通常可以这样做。然而,我确实同意,如果在里面烤会容易得多。
恐怕我已经不再关注VC++的进展了,所以我不知道它现在在哪里。我唯一的建议是…在组装级别查找。
我听说它已经在vs2010中实现了,但找不到任何参考。无论如何,在c++0x标准中,明确要求这样的初始化是线程安全的,所以我想ms迟早会遵守。
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- 如何让MSVC编译器优化多步POD初始化?
- MSVC 2017 在单个翻译单元中违反静态初始化顺序
- C++指向成员的指针的类内初始化会使 MSVC 失败(但 GCC/Clang 工作)
- 为什么静态局部变量的 MSVC 线程安全初始化使用 TLS
- 值初始化:MSVC 与 clang
- 为什么使用 MSVC 编译这个不正确的 std::函数初始化?
- 在MSVC上的数组初始化期间,destructor在不复制或移动构造方的情况下调用
- 为什么 MSVC 和 GCC 不能使用具有默认值的字段初始化结构
- MSVC 19.11 / Visual C 2017:尺寸1和size_t类型的初始化列表误解
- 使用MSVC 2013的类初始化器中的C++11
- 静态 const 数组在 MSVC 中动态初始化
- MSVC和Clang之间的大括号不一致或初始化行为相等
- 当涉及填充时,堆的MSVC初始化
- 我如何让MSVC把未初始化的数据在.bss
- MSVC是否保证在未初始化的本地字符数组中为空字符?
- 本地静态的线程安全初始化:MSVC
- 在MSVC编译器下使用最大成员初始化联合
- 使用双精度的 MSVC 大括号初始化似乎违反了该标准
- 在MSVC和GCC上声明和初始化constexpr的通用语法