假设有一个函数(可能是成员函数)
SomeType foo()
{
static SomeType var = generateVar();
return var;
}
如果同时从多个线程“第一次”调用var
,将如何初始化foo
?
generateVar()
在任何情况下只会被调用一次(如果使用的话)?foo
将返回相同的值?答案 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}}抛出)。