c++ - 异常调用后是否保证 std::call_once 的线程通知

标签 c++ multithreading c++11

std::call_once 的标准示例 cppreference.com以这种方式描述异常调用的行为,据我了解,其他线程等待第一个进入 std::call_once 并且在发生异常的情况下,下一个线程将尝试执行 std::call_once。虽然在线编译器确认了这种行为,但我无法在本地重现它。对于最小的例子

#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();
}

复制自cppreference.com执行在第一次抛出后卡住并永远运行

编译是用g++-5 -std=c++14 source.cpp -pthread (version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609) 或 clang++-6.0 source.cpp -pthread (version clang version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)) .

将更多输出放入代码显示,所有线程都已启动,但只有最先抛出的线程才会结束。所有其他人似乎都在 std::call_once 声明之前等待。因此我的问题是:是否保证通知正在等待第一个线程完成的线程?

最佳答案

Is the notification of threads that are waiting for the first thread to finish guaranteed?

不涉及通知,但如果我将您的问题解释为:

Is t4.join() guaranteed to return?

是的。

[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.
An execution of call_­once that calls its func is an active execution. An active execution shall call 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.
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.

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.

A call_once 仅当另一个call_once时才会执行返回(意思是:没有抛出)。由于观察到总顺序,因此可以保证:

  • t1是主动异常执行还是被动执行;
  • t2是主动异常执行还是被动执行;
  • t3是主动返回执行;
  • t4是主动异常执行还是被动执行;

由于被动执行返回,t4保证返回。


user cpplearner 报告, a bug of pthread_once 使问题中列出的程序挂起(demo)。

关于c++ - 异常调用后是否保证 std::call_once 的线程通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57390526/

相关文章:

java - SwingWorker的execute()方法似乎没有做任何事情

android - 线程和音频同时播放

c++ - const 变量的值在常量表达式中是否可用,取决于变量类型

c++ - 通过模拟调试CGI

c++ - 没有变量说明符的模板参数上的 SFINAE(enable_if)

java - 处理线程最大执行时间的最佳方法(在 Java 中)

c++ - 实例化/模板函数专门化

python - 修改静态变量是线程安全的吗?

c++ - boost::shared_ptr 中的 ref_count

c++ - 为什么某些东西在调试器打开时永远不会崩溃?