多线程环境中的静态局部变量初始化
Static local variable initialisation in multithreaded environment
假设存在一个函数(可能是成员函数)
SomeType foo()
{
static SomeType var = generateVar();
return var;
}
如果foo
将从多个线程同时"第一次"调用,var
将如何初始化?
- 是否保证
generateVar()
在任何情况下只被调用一次(当然如果使用的话)? - 是否保证
foo
在任何场景下多次调用时会返回相同的值? - 原始类型和非原始类型在行为上有区别吗?
关于c++ 03:
c++ 03标准定义的抽象机没有包含一个正式的定义,即什么是线程,如果一个对象被并发访问,程序的结果应该是什么。没有同步原语、在不同线程中执行的操作排序、数据竞争等概念。因此,根据定义,每个多线程c++ 03程序都包含未定义行为。
当然,在实践中实现确实提供了一个文档化的行为,但是在标准中并没有指定这个行为应该是什么。因此,我认为这取决于你的编译器。答案的其余部分将集中在c++ 11上,它确实定义了并发操作的语义。
关于c++ 11:
是否保证
generateVar()
在任何场景中只被调用一次(当然如果使用的话)?
不,在任何情况下都不会。
var
的初始化保证是线程安全的,因此generateVar()
不会并发进入,但是如果generateVar()
抛出异常,或者SomeType
的复制构造函数或移动构造函数抛出异常(当然,如果SomeType
是UDT),那么在下一次执行流进入声明时将重新尝试初始化-这意味着generateVar()
将再次被调用。
根据c++ 11标准第6.7/4段关于静态存储持续时间:
的块作用域变量的初始化[…如果通过抛出异常退出初始化,初始化将被终止不完整,因此下次控件进入声明时将再次尝试。如果控制进入当变量被初始化时并发声明,应等待并发执行初始化完成。If控件在变量被指定时递归地重新进入声明初始化后,行为未定义。[…]
关于你的下一个问题:
是否保证foo在任何情况下多次调用时会返回相同的值?
如果它能够返回一个值(见上文),那么是。
基本类型和非基本类型的行为有区别吗?
不,没有,除了没有基本类型的复制构造函数或移动构造函数这样的东西,所以也没有复制初始化导致抛出异常的风险(当然,除非generateVar()
抛出)。
相关文章:
- 为什么C++有不同的变量初始化方式?
- 静态 constexpr 成员变量初始化
- C++不同的变量初始化
- 全局和局部变量初始化与 constexpr 的差异背后的基本原理
- 是变量初始化失败吗?
- 视觉C++:在 DLL 加载期间,全局变量初始化顺序是否具有确定性?
- 类静态变量初始化顺序
- 使用 constinit 变量初始化 constexpr 变量
- 是否可以在不修改父类的情况下将成员变量初始化推迟到继承的类?
- 如何将局部变量初始化为C++的未知值
- 使用全局变量初始化不同编译单元中的其他全局变量
- 使用默认构造函数引用成员变量初始化错误
- 宏的 if 语句中的变量初始化
- 不稳定的C :每行适应性变化多变量初始化
- DLL 中的 C++ 静态局部变量初始化会导致_CrtIsValidHeapPointer异常
- C++-局部未初始化变量的值
- 在VS2015中c++局部静态变量初始化线程安全吗?
- 多线程环境中的静态局部变量初始化
- 局部静态变量初始化是线程安全的
- C++11 中线程安全局部静态变量初始化的成本