简体   繁体   English

在异常调用之后是std :: call_once保证线程的通知

[英]Is notification of threads guaranteed for std::call_once after exceptional call

The standard example for std::call_once on cppreference.com describes the behavior for exceptional calls that way, that to my understanding other threads wait for the first entering the std::call_once and in case of an exception the next thread will try to execute the std::call_once . cppreference.comstd::call_once的标准示例描述了异常调用的行为,这是我理解的其他线程等待第一次进入std::call_once ,如果是异常,下一个线程将尝试执行std::call_once While online compilers confirm this behavior, I cannot reproduce it locally. 虽然在线编译器确认了这种行为,但我无法在本地重现它。 For the minimal example 对于最小的例子

#include <iostream>
#include <thread>
#include <mutex>

std::once_flag flag;

void may_throw_function(bool do_throw)
{
  if (do_throw) {
    std::cout << "throw: call_once will retry\n";
    throw std::exception();
  }
  std::cout << "Didn't throw, call_once will not attempt again\n";
}

void do_once(bool do_throw)
{
  try {
    std::call_once(flag, may_throw_function, do_throw);
  }
  catch (...) {}
}

int main()
{
    std::thread t1(do_once, true);
    std::thread t2(do_once, true);
    std::thread t3(do_once, false);
    std::thread t4(do_once, true);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

copied from cppreference.com the execution is stuck after the first throw and runs forever cppreference.com复制后,执行在第一次投掷后被卡住并永远运行

Compilation is done with g++-5 -std=c++14 source.cpp -pthread (version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609 ) or clang++-6.0 source.cpp -pthread (version clang version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) ). 编译使用g++-5 -std=c++14 source.cpp -pthread (版本g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609 )或clang++-6.0 source.cpp -pthread (版本) clang version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final) )。

Putting more output into the code shows, that all threads are started, but only the threads that throws first ever ends. 将更多输出放入代码中会显示所有线程都已启动,但只有先抛出的线程才会结束。 All others seems to wait before the std::call_once statement. 所有其他人似乎都在std::call_once语句之前等待。 Hence my question: Is the notification of threads that are waiting for the first thread to finish guaranteed? 因此我的问题是:等待第一个线程的线程通知是否有保证?

Is the notification of threads that are waiting for the first thread to finish guaranteed? 是否等待第一个线程完成保证的线程通知?

There is no notification involved, but if I interpret your question as: 没有涉及通知,但如果我将您的问题解释为:

Is t4.join() guaranteed to return? t4.join()保证返回吗?

Yes it is. 是的。

[thread.once.callonce]

 template<class Callable, class... Args> void call_once(once_flag& flag, Callable&& func, Args&&... args); 

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 its func is an active execution. 调用其func的call_once的执行是一个活动执行。 An active execution shall call INVOKE(​std::forward<Callable>(func), std::forward<Args>(args)...) . 活动执行应调用INVOKE(​std::forward<Callable>(func), 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 given once_flag : at most one shall be a returning execution; 在任何给定的once_flagcall_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 . 只有在返回执行时才会执行被动执行

Synchronization : For any given once_flag: all active executions occur in a total order ; 同步 :对于任何给定的once_flag: 所有活动执行都按总顺序发生 ; 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. 并且返回的执行与所有被动执行的返回同步。

A call_once will not be executed only if another call_once returned (meaning: did not throw). 一个call_once 只有 1人将不被执行call_once返回(:没扔的意思)。 And since total order is observed, it is guaranteed that: 由于遵守了总订单,因此可以保证:

  • t1 is an active exceptional execution or a passive execution; t1是主动例外执行或被动执行;
  • t2 is an active exceptional execution or a passive execution; t2是主动例外执行或被动执行;
  • t3 is an active returning execution; t3是主动返回执行;
  • t4 is an active exceptional execution or a passive execution; t4是主动例外执行或被动执行;

And since a passive execution returns, t4 is guaranteed to return. 并且由于被动执行返回,因此保证t4返回。


Reported by user cpplearner , a bug of pthread_once make the program listed in the question hang ( demo ). 用户cpplearner报告pthread_once的错误使问题中的程序挂起( 演示 )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM