2016-03-24 44 views
3

问题 std ::未来调用wait()或get()销毁?std ::未来等待破坏

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

为什么要这样做?如果不使用该结果,为什么它应该等待结果可用? – user463035818

+3

只有当它由'std :: async'创建时才会被阻止。 – Simple

+2

答案是否定的,除非是肯定的。 –

回答

3

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

在这个问题上是异步的析构函数不应该阻止我们专门的讨论 很大就可以了。 [..] 收到 相当大的支持的唯一位置是[..]给出的建议,未来的析构函数 不会阻止,除非从异步返回,使其成为值得注意的 异常。 [..]经过重大讨论,我们试图运行的唯一部分是N3776,试图澄清未来和〜shared_future不可能阻止除异步存在 之外的位置。有人企图按照C的 这一行的方式发布弃用,而不用替换。这个议案实际上是几乎提出 。但[...]甚至在达到手术台 之前就已经死亡。

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

的基本问题,通过异步返回

期货()在其 析构函数相关的共享状态异步启动策略等待准备就绪。这个 可以防止相关线程继续运行的情况,并且不再需要等待它完成的方式,因为关联的未来已经被销毁。如果没有对 进行英勇的努力,否则等待完成,这样的“失控”线程可以继续运行超过它所依赖的对象的生命周期。

举个例子,考虑下面两个函数:

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过去它的寿命的内存 。

最终结果可能是类似 的交叉线程“内存粉碎”,类似于N2802中类似条件下的描述。

如果get()或wait()在 no_join_async()生成的未来销毁之前被调用,则当然可以避免该问题。与N2802一样, 的难题在于意外的异常可能导致 代码被绕过。因此,为了确保安全,需要某种示范警卫通常是 。如果程序员忘记添加范围 后卫,攻击者很可能会产生例如一个 bad_alloc异常在适当的时候利用 监督,并导致堆栈被覆盖。有可能 也控制用于覆盖堆栈的数据,从而控制整个过程。这是一个非常微妙的错误,在我们的经验 中,它很可能在实际代码中被忽略。

+0

如果我理解正确。答案是视情况而定。 – user1235183

+1

@ user1235183: - 是的,你可以说:) –

+0

请引用_standard_。这些都不是对实际行为的权威性声明。 –