std :: future是否等待销毁

时间:2016-03-24 10:20:08

标签: c++ concurrency

问题 std :: future会在销毁时调用wait()或get()吗?

示例

void fun()
{
     std::future<int> fut = my_thread_pool.submit(some_work);
}//is fut.wait() or fut.get() called? here

1 个答案:

答案 0 :(得分:3)

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

  

关于异步析构函数不应该阻止的问题,我们投入了一个   关于它的大量讨论。 [...] 收到的唯一立场   相当大的支持是[...]提供未来析构者的咨询   不会阻止,除非从异步返回,使其成为值得注意的   例外。 [..]经过重大讨论,我们唯一的一部分   试图携带的是N3776,试图澄清其立场   〜将来和~socred_future除非可能存在,否则不会阻止   异步。曾试图沿着这条线发布弃用   C.无需替换即可弃用异步。这个动议实际上是   几乎提出来了。但是[..]它甚至在它到达之前就已经死了   手术台。

同时检查:N3679: Async() future destructors must wait

  

基本问题

     

async()返回的期货与异步启动策略等待   用于关联共享状态的析构函数。这个   防止关联线程继续运行的情况,   并且不再有等待它完成的手段,因为   相关的未来已被破坏。没有英勇的努力   否则等待完成,这样的&#34;逃跑&#34;线程可以继续   超过它所依赖的对象的生命周期。

     

例如,考虑以下一对功能:

void f() {
  vector<int> v;
  ...
  do_parallel_foo(v);
  ...
}

void do_parallel_foo(vector<int>& v) {
  auto fut = no_join_async([&] {...  foo(v); return ...; });
  a: ...
  fut.get();
  ...
}
     

如果no_join_async()返回析构函数不等待的未来   异步完成,一切都可能正常,直到抛出的代码   一个例外。那时没有等待异步完成,   它可能继续从do_parallel_foo()的出口运行   和f(),导致异步任务访问和覆盖内存   以前分配给v超过它的一生。

     

最终结果很可能是一个跨线程&#34;内存粉碎&#34;类似   在类似条件下在N2802中描述的那种。

     

如果调用get()或wait(),当然可以避免这个问题   no_join_async() - 在销毁之前生成的期货。该   难度,如在N2802中,是一个意外的异常可能导致   要绕过的代码。因此通常会有某种范围的守卫   需要确保安全。如果程序员忘记添加范围   警卫,似乎攻击者可能会产生例如一个   bad_alloc异常在适当的时候利用了   疏忽,并导致堆栈被覆盖。有可能   还控制用于覆盖堆栈的数据,从而获得增益   控制过程。这是一个足够微妙的错误,在   根据我们的经验,它可能会在实际代码中被忽略。