【问题标题】:Why is the destructor of a future returned from `std::async` blocking?为什么从`std::async`阻塞返回的future的析构函数?
【发布时间】:2014-06-20 17:30:38
【问题描述】:

当试图回答另一个Stackoverflow question 时,我意识到这个简单的 C++11 sn-p 正在隐式阻塞调用线程:

std::async(std::launch::async, run_async_task)

对我来说,这似乎是规范的 C++11 异步启动任务而不关心结果的方式。相反,为了实现这一点,显然必须明确地创建和分离一个线程(参见answer 提到的问题)。

所以这是我的问题:在安全/正确性方面,std::future 的析构函数是否必须阻塞?如果它只阻塞get 会不会足够,否则,如果我对返回值或异常不感兴趣,它只是触发并忘记?

【问题讨论】:

  • 刚刚回复了您的评论,在这里您有一个问题,哈哈
  • @texasbruce:是的,因为它真的让我很烦。我确信这是 新的 C++11y 方法,即使我不关心结果,我也很惊讶地看到它会阻塞(仅在最后的一个注释中提到)。除非有明确的必要性,否则我认为这不是一个好的界面。
  • 我相信这是对 c++14 提出的更改之一,可以按照您的预期进行。
  • @W.B.:AFAIK 的一个建议是引入then 方法,以便您可以以异步方式组合期货。我希望他们也能在那时修复这种行为。

标签: c++ multithreading c++11 asynchronous std


【解决方案1】:

阻塞 std::async 返回的期货和线程的析构函数:这是一个有争议的话题。以下按时间顺序排列的论文列表反映了委员会成员的一些讨论:

尽管有很多讨论,但 C++14 没有计划对 std::future 和 std::thread 的析构函数的阻塞行为进行更改em>。

关于您的问题,最有趣的论文可能是 Hans Boehm 的第二篇论文。我引用一些部分来回答你的问题。

N3679: Async() future destructors must wait

[..] async() 返回的带有async 启动策略的期货在其析构函数中等待相关的共享状态准备就绪。这防止了关联线程继续运行的情况,并且不再有方法等待它完成,因为关联的未来已被破坏。如果不努力等待完成,这样一个“失控”的线程可以在它所依赖的对象的生命周期之后继续运行。

[示例]

最终的结果很可能是跨线程“内存粉碎”。如果get() 或wait() 在它们[期货] 被销毁之前被调用[..],这个问题当然可以避免。困难 [..] 是意外的异常可能导致该代码被绕过。因此,通常需要某种范围保护来确保安全。如果程序员忘记添加范围保护,攻击者可能会生成例如一个 bad_alloc 异常在适当的时候利用监督,并导致堆栈被覆盖。还可以控制用于覆盖堆栈的数据,从而获得对进程的控制。这是一个非常微妙的错误,根据我们的经验,它很可能在实际代码中被忽略。

更新:Michael Wong 的旅行报告还包含一些关于 2013 年 9 月会议成果的有趣信息:

The View from the C++ Standard meeting September 2013 Part 2 of 2.

关于异步析构函数不应阻塞的问题,我们进行了大量讨论。 [..] 唯一获得大量支持的立场是 [..] 建议未来的析构函数不会阻塞,除非从异步返回,这使它成为一个值得注意的例外。 [..] 经过大量讨论,我们尝试携带的唯一部分是 N3776,试图澄清~future 和~shared_future 除非可能存在异步,否则不会阻塞的立场。尝试按照 C 的方式发布弃用。弃用异步而不替换。这个议案实际上几乎是提出来的。但是 [..] 它甚至在到达手术台之前就死了。

【讨论】:

  • 太好了,正是我正在寻找的答案!仍然不相信这是正确的决定,但至少我现在清楚权衡取舍。我猜这是 RAII 的某种极端形式,比如确保文件处理程序在析构函数中关闭。
  • 关于它在 C++14 中的修复,这个提议对我来说听起来像是:n3773。或者至少它使您可以手动“分离”。
  • 我确信我已经看到了一些关于讨论结果的信息。现在我找到了并更新了答案。
  • 虽然行为不会改变,但并发TS的std::future::then()看起来可以在这里使用。 then返回的std::future好像不是同一种,所以如果被破坏就不需要阻塞了。 std::async( []{ sleep(20); } ).then( []{} ); return;
  • 从上面看不清楚,但是N3776进入了C++14。
猜你喜欢
  • 1970-01-01
  • 2020-12-29
  • 1970-01-01
  • 2014-11-06
  • 2020-01-02
  • 2020-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多