Multithreading std::call_once和函数级静态初始化之间的区别是什么
1) std::给你打一次电话Multithreading std::call_once和函数级静态初始化之间的区别是什么,multithreading,c++11,Multithreading,C++11,1) std::给你打一次电话 A a; std::once_flag once; void f ( ) { call_once ( once, [ ] { a = A {....}; } ); } 2) 功能级静态 A a; void f ( ) { static bool b = ( [ ] { a = A {....}; } ( ), true ); } 这两个代码段具有相同的行为,即使在初始化过程中出现异常也是如此 此结论基于(我对)c++11标准(草案n3337
A a;
std::once_flag once;
void f ( ) {
call_once ( once, [ ] { a = A {....}; } );
}
2) 功能级静态
A a;
void f ( ) {
static bool b = ( [ ] { a = A {....}; } ( ), true );
}
这两个代码段具有相同的行为,即使在初始化过程中出现异常也是如此 此结论基于(我对)c++11标准(草案n3337)的以下引用:
- 1第6.7节声明声明第4条规定:
void f ( ) {
static bool b = ( [ ] { a = A {....}; } ( ), true );
}
void f ( ) {
call_once ( once, [ ] { a = A {....}; } );
b
保证只初始化一次,意味着lambda只执行(成功)一次,意味着a=a{…}代码>仅执行(成功)一次
- 2第30.4.4.2节函数调用一次说明:
不调用func的call_once执行是被动执行。调用其func的call_once的执行是活动执行。活动执行应调用INVOKE(decage\u COPY(std::forward(func))、decage\u COPY(std::forward(args))…)。如果对func的此类调用引发异常,则执行异常,否则返回异常。异常执行应将异常传播给call_的调用方一次在任何给定的once_标志的所有call_once执行中:最多一个是返回执行如果有返回执行,则应为最后一次活动执行;只有当有返回执行时,才会有被动执行
这意味着:
void f ( ) {
static bool b = ( [ ] { a = A {....}; } ( ), true );
}
void f ( ) {
call_once ( once, [ ] { a = A {....}; } );
std::call_once
的lambda参数仅执行(成功)一次,意思是a=a{…}代码>仅执行(成功)一次
在这两种情况下,a=a{…}代码>仅执行(成功)一次。对于您的示例用法,hmjd的回答充分解释了没有区别(除了在call\u once
案例中需要额外的全局once\u标志
对象)。但是,call\u once
案例更灵活,因为once\u标志
对象没有绑定到单个作用域。例如,它可以是一个类成员,并可由多个函数使用:
class X {
std::once_flag once;
void doSomething() {
std::call_once(once, []{ /* init ...*/ });
// ...
}
void doSomethingElse() {
std::call_once(once, []{ /*alternative init ...*/ });
// ...
}
};
现在,根据首先调用哪个成员函数,初始化代码可能会有所不同(但对象仍将只初始化一次)
因此,对于简单的情况,局部静态可以很好地工作(如果编译器支持的话),但是有一些不太常见的用法可能更容易用call\u once
实现。您的两个示例并不相同,call\u once
忽略您传递给它的可调用对象的返回值。您可能希望在两个lambda表达式中都分配给a
。是的,我忘了更改第一个表达式。fixedIt可能不必要地迂腐,但我认为标准语言(至少引用的部分-可能还有其他章节对此进行了更详细的说明)并不一定意味着lambda将只执行一次,而只是计算结果将只分配给变量一次。防止并行执行的内容的粒度可能未指定或由实现定义。