std::call_once 是阻塞调用吗?
Is std::call_once a blocking call?
我在我的代码中使用 std::call_once
只初始化一些共享变量一次。调用代码位于由多个线程触发的回调中。
我有兴趣知道,因为我在文档中找不到它,所以 std::call_once
是否基本上像 std::lock_guard
一样阻塞?
在实践中看起来是这样的。
例如,以下将在调用任何 print()
之前打印 "Done"
:
#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
确实会被调用一次但允许其他线程继续并忽略此调用?
是std::call_once
是阻塞调用。从 [thread.once.callonce] 我们有
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 ]
Synchronization: For any given once_flag
: all active executions occur in a total order; completion of an active execution synchronizes with (1.10) the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions.
强调我的
这意味着所有对 call_once
的调用都将等到传递给 call_once
的函数完成。在您的情况下,这意味着必须在任何线程调用 print()
之前调用 do_once()
我在我的代码中使用 std::call_once
只初始化一些共享变量一次。调用代码位于由多个线程触发的回调中。
我有兴趣知道,因为我在文档中找不到它,所以 std::call_once
是否基本上像 std::lock_guard
一样阻塞?
在实践中看起来是这样的。
例如,以下将在调用任何 print()
之前打印 "Done"
:
#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
确实会被调用一次但允许其他线程继续并忽略此调用?
是std::call_once
是阻塞调用。从 [thread.once.callonce] 我们有
Effects: An execution of call_once that does not call its
func
is a passive execution. An execution of call_once that calls itsfunc
is an active execution. An active execution shall callINVOKE (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 ofcall_once
for any givenonce_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 ]Synchronization: For any given
once_flag
: all active executions occur in a total order; completion of an active execution synchronizes with (1.10) the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions.
强调我的
这意味着所有对 call_once
的调用都将等到传递给 call_once
的函数完成。在您的情况下,这意味着必须在任何线程调用 print()
do_once()