21

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

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

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

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

1 回答 1

28

关于 C++03:

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

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

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

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

关于 C++11:

是否保证generateVar()在任何情况下都只会调用一次(当然如果使用)?

不,在任何情况下都不会。

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

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

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

关于你的下一个问题:

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

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

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

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

于 2013-05-24T12:30:25.777 回答