gpt4 book ai didi

c++ - std::call_once 和内存重新排序

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:31:02 26 4
gpt4 key购买 nike

给定来自 here 的代码:

class lazy_init
{
mutable std::once_flag flag;
mutable std::unique_ptr<expensive_data> data;

void do_init() const
{
data.reset(new expensive_data);
}
public:
expensive_data const& get_data() const
{
std::call_once(flag,&lazy_init::do_init,this);
return *data;
}
};

我在其他地方也看到了相同模式的一些变体。所以我的问题是:为什么这段代码被认为是保存的?以及为什么编译器不能在调用 std::call_once 之前只读取 data 并以不正确的数据结束?例如

tmp = data.get();
std::call_once(flag,&lazy_init::do_init,this);
return *tmp;

我的意思是我没有发现任何可以阻止这种情况的障碍。

最佳答案

如果允许编译器生成与您描述的内容相匹配的代码,则基本上不可能使用 C++ 进行编程。

这在 §1.9/14 程序执行 (n3290) 中说明:

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

你的 return语句在前面的完整表达式之后排序。编译器必须输出代码,就好像在计算 return 语句之前,前面语句的所有副作用都已被完全计算。
您的示例不遵守该规则,因为它评估了 *data在考虑 std::call_once(...) 的副作用之前完整的表达。

此外,std::call_once在其描述中有这个(§30.4.4.2/2 和 3):

2/ Effects: An execution of call_once that does not call its func is a passive execution. An execution of call_once that calls its func is an active execution. An active execution shall call INVOKE (DECAY_-
COPY ( std::forward<Callable>(func)), DECAY_COPY (std::forward<Args>(args))...)
. If such a call to func throws an exception the execution is exceptional, otherwise it is returning. An exceptional execution shall propagate the exception to the caller of call_once. Among all executions of call_once for any given once_flag: at most one shall be a returning execution; if there is a returning execution, it shall be the last active execution; and there are passive executions only if there is a returning execution. [ Note: passive executions allow other threads to reliably observe the results produced by the earlier returning execution. — end note ]

3/ Synchronization: For any given once_flag: all active executions occur in a total order; completion of an active execution synchronizes with the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions.

因此标准要求同步以适合您的用例。

关于c++ - std::call_once 和内存重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9964786/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com