[英]Is std::call_once a blocking call?
I'm using std::call_once
in my code to initialize some shared variables only once. 我在我的代码中使用
std::call_once
只初始化一些共享变量一次。 The calling code is inside a callback that is triggered by multiple threads. 调用代码位于由多个线程触发的回调内。 What I'm interested to know, since I couldn't find it in the documentation is whether
std::call_once
is blocking essentially as if there was a std::lock_guard
instead? 我有兴趣知道,因为我在文档中找不到它是
std::call_once
是否阻塞,就好像有一个std::lock_guard
? In practice it looks like this is the case. 在实践中,看起来就是这种情况。
For example, the following will print "Done"
before any print()
will be called: 例如,以下将在调用任何
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));
}
I'm assuming this is indeed the case (since I don't see how it could be implemented otherwise), but is this behavior guaranteed or could there be a compiler that decides that std::call_once
will indeed be called once but allow other threads to continue and just ignore this call? 我假设情况确实如此(因为我看不出它是如何实现的),但这种行为是否得到保证,或者是否有编译器决定
std::call_once
确实会被调用一次但是允许其他线程继续,只是忽略这个调用?
Yes std::call_once
is a blocking call. 是的
std::call_once
是一个阻塞调用。 From [thread.once.callonce] we have 来自[thread.once.callonce]我们有
Effects: An execution of call_once that does not call its
func
is a passive execution.效果:不调用其
func
的call_once的执行是被动执行。 An execution of call_once that calls itsfunc
is an active execution.调用其
func
的call_once的执行是一个活动执行。 An active execution shall callINVOKE (DECAY_COPY ( std::forward<Callable>(func)), DECAY_COPY (std::forward<Args>(args))...)
.活动执行应调用
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.如果对func的这种调用抛出异常,则执行异常,否则返回。 An exceptional execution shall propagate the exception to the caller of call_once.
异常执行应将异常传播给call_once的调用者。 Among all executions of
call_once
for any givenonce_flag
: at most one shall be a returning execution;在任何给定的
once_flag
的call_once
所有执行中:最多一个应该是返回执行; 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;同步:对于任何给定的
once_flag
:所有活动执行都按总顺序发生; completion of an active execution synchronizes with (1.10) the start of the next one in this total order;活动执行的完成与(1.10)该总订单中下一个的开始同步; and the returning execution synchronizes with the return from all passive executions.
并且返回的执行与所有被动执行的返回同步。
emphasis mine 强调我的
This means that all calls to call_once
will wait until the function passed to call_once
completes. 这意味着对
call_once
所有调用都将等待,直到传递给call_once
的函数完成。 In your case that means do_once()
must be called before any thread calls print()
在你的情况下,这意味着必须在任何线程调用
print()
之前调用do_once()
print()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.