当我尝试回答另一个Stackoverflow question时,我意识到这个简单的C++11片段隐式地阻塞了调用线程:
std::async(std::launch::async, run_async_task)对我来说,这似乎是一种规范的C++11方法,可以异步启动任务,而不关心结果。相反,为了实现这一点,人们必须显式地创建和分离线程(请参阅上述问题的answer )。
所以我的问题是:在安全性/正确性方面,std::future的析构函数必须阻塞吗?如果它只在get上阻塞,这还不够吗?否则,如果我对返回值或异常不感兴趣,它只是触发并忘记?
发布于 2014-05-05 02:39:25
阻塞std::async和线程:返回的期货的析构函数,这是一个有争议的话题。以下按时间顺序列出的文件反映了委员会成员的一些讨论:
尽管有很多讨论,但对于std::future和std::thread的析构函数的阻塞行为,C++14还没有计划的改变。
关于你的问题,最有趣的论文可能是汉斯·博姆的第二篇论文。我引用一些部分来回答你的问题。
。。使用async启动策略的async()返回的未来在其析构函数中等待关联的共享状态变为就绪。这可以防止关联线程继续运行,并且不再有等待线程完成的方法,因为关联的未来已被销毁。如果没有英雄式的努力来等待完成,这样的“失控”线程可以在它所依赖的对象的生命周期之后继续运行。
示例
最终的结果很可能是跨线程的“内存崩溃”。如果调用get()或wait(),这个问题当然可以避免。在他们的未来被摧毁之前。困难的是..意外异常可能导致代码被绕过。因此,通常需要某种作用域保护来确保安全。如果程序员忘记添加作用域保护,攻击者很可能会在适当的时候生成bad_alloc异常,以利用该疏忽,并导致堆栈被覆盖。也可以控制用于重写堆栈的数据,从而获得对过程的控制。这是一个非常微妙的错误,在我们的经验中,它很可能在真实的代码中被忽略。
更新: Michael Wong的行程报告还包含了一些关于2013年9月会议结果的有趣信息:
关于异步析构函数不应该阻塞的问题,我们对此进行了大量的讨论。。。唯一得到相当多支持的职位是..建议未来的析构函数不会阻塞,除非从异步返回,这使它成为值得注意的异常。。。在重要的讨论之后,我们试图实现的唯一部分是N3776,试图澄清~future和~shared_future不会阻止的位置,除非可能存在异步。有人试图发出类似于C的弃用命令。弃用异步而不进行替换。这项议案其实是差一点提出的。但是..。它甚至在到达手术台之前就死了。
https://stackoverflow.com/questions/23455104
复制相似问题