多线程环境中的静态局部变量初始化

And*_*rew 19 c++ multithreading initialization c++11 c++03

假设有一个函数(可能是成员函数)

SomeType foo()
{
    static SomeType var = generateVar();
    return var;
}
Run Code Online (Sandbox Code Playgroud)

var如果foo将同时从多个线程"第一次"调用,将如何初始化?

  1. 是否保证generateVar()在任何情况下只调用一次(如果使用的话)?
  2. 是否保证foo在任何情况下多次调用时都会返回相同的值?
  3. 原始类型或非原始类型的行为是否存在差异?

And*_*owl 25

关于C++ 03:

由C++ 03标准定义的抽象机器不包含线程是什么的正式定义,以及如果同时访问对象,程序的结果应该是什么.

没有同步原语的概念,在不同线程中执行的操作的排序,数据竞争等等.因此,根据定义,每个多线程C++ 03程序都包含未定义的行为.

当然,在实践中,实现确实提供了记录的行为,但标准中没有任何内容指定此行为应该是什么.因此,我会说这取决于你的编译器.

其余的答案将集中在C++ 11上,它确实定义了并发操作的语义.

关于C++ 11:

是否保证generateVar()在任何情况下只调用一次(如果使用的话)?

不,不是在任何情况下.

初始化var保证是线程安全的,所以generateVar()不会同时输入,但是如果抛出异常generateVar(),或者由复制构造函数或移动构造函数抛出SomeType(SomeType当然,如果是UDT),那么初始化将是下次执行流程进入声明时重新尝试 - 这意味着generateVar()将再次调用.

根据C++ 11标准的6.7/4段,初始化具有静态存储持续时间的块范围变量:

[...]如果初始化通过抛出异常退出,则初始化未完成,因此下次控制进入声明时将再次尝试.如果控制在初始化变量时同时进入声明,则并发执行应等待初始化完成.如果控件在初始化变量时以递归方式重新输入声明,则行为未定义.[...]

关于你的下一个问题:

是否保证foo在任何场景中多次调用时都会返回相同的值?

如果它将设法返回一个值(见上文),那么是.

原始类型或非原始类型的行为是否存在差异?

不,没有,除了没有复制构造函数或原始类型的移动构造函数这样的东西,因此复制初始化也不会导致抛出异常(除非当然generateVar()抛出).

  • @Devolus:当执行流程满足其声明时,块范围中的静态变量被初始化.我在标准中添加了引用 (3认同)
  • @Andrew:C++ 98,以及C++ 03,没有定义"线程"的概念,所以每个多线程程序都有(正式)未定义的行为.我猜其他一切都是特定于实现的 (2认同)