我在用着std::call_once
在我的代码中仅初始化一些共享变量一次。调用代码位于由多个线程触发的回调内。
我有兴趣知道,因为我在文档中找不到它是否std::call_once
本质上是阻塞的,就好像有一个std::lock_guard
反而?
实际情况看起来确实如此。
例如,将打印以下内容"Done"
在任何之前print()
将被称为:
#include <future>
#include <iostream>
#include <thread>
#include <mutex>
std::once_flag flag;
void print()
{
for(int i=0;i<10;i++)
{
std::cout << "Hi, my name is " << std::this_thread::get_id()
<< ", what?" << std::endl;
}
}
void do_once()
{
std::cout << "sleeping for a while..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Done" << std::endl;
}
void work()
{
std::call_once(flag, [](){ do_once(); });
print();
}
int main()
{
auto handle1 = std::async(std::launch::async, work);
auto handle2 = std::async(std::launch::async, work);
auto handle3 = std::async(std::launch::async, work);
auto handle4 = std::async(std::launch::async, work);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
我假设确实如此(因为我不知道如何以其他方式实现它),但是这种行为是否得到保证,或者是否有编译器决定std::call_once
确实会被调用一次,但允许其他线程继续并忽略此调用?
Yes std::call_once
是一个阻塞调用。从 [thread.once.callonce] 我们有
Effects:执行 call_once 但不调用其func
是一种被动的执行。调用它的 call_once 的执行func
是主动执行。主动执行应调用INVOKE (DECAY_COPY ( std::forward<Callable>(func)), DECAY_COPY (std::forward<Args>(args))...)
。如果这样的 func 调用抛出异常,则执行异常,否则返回。异常执行应将异常传播给 call_once 的调用者。在所有处决中call_once
对于任何给定的once_flag
:至多一次应为返回处决;如果有返回
执行,它应该是最后一个活跃的执行;仅当有返回执行时才会有被动执行。[注意:被动执行允许其他线程可靠地观察较早返回的执行产生的结果。 ——尾注]
同步:对于任意给定的once_flag
:所有活动执行均按总顺序发生;活动执行的完成与 (1.10) 总顺序中下一个执行的开始同步;并且返回的执行与所有被动执行的返回同步。
emphasis mine
这意味着所有调用call_once
将等到函数传递给call_once
完成。在你的情况下,这意味着do_once()
必须在任何线程调用之前调用print()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)