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



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

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

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

  1. 是否保证generateVar()在任何情况下只被调用一次(当然如果使用的话)?
  2. 是否保证foo在任何场景下多次调用时会返回相同的值?
  3. 原始类型和非原始类型在行为上有区别吗?

关于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()抛出)。

最新更新