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

时间:2013-05-24 12:27:10

标签: c++ multithreading c++11 initialization c++03

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

SomeType foo()
{
    static SomeType var = generateVar();
    return var;
}

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

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

1 个答案:

答案 0 :(得分:25)

关于C ++ 03:

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

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

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

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

关于C ++ 11:

  

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

不,不是在任何情况下。

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

关于使用静态存储持续时间初始化块范围变量的C ++ 11标准的第6.7 / 4段:

  

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

关于你的下一个问题:

  

在任何情况下多次调用foo时,是否可以保证foo会返回相同的值?

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

  

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

不,没有,除了没有复制构造函数或原始类型的移动构造函数之外,因此复制初始化也不会导致抛出异常(当然除非{ {1}}抛出)。