并发 TS:std::future<...>::then,如何在不存储返回的未来的情况下保持链存活?
Posted
技术标签:
【中文标题】并发 TS:std::future<...>::then,如何在不存储返回的未来的情况下保持链存活?【英文标题】:Concurrency TS: std::future<...>::then, how to keep the chain alive without storing the returned future? 【发布时间】:2015-12-11 13:38:45 【问题描述】:我正在构建一组在事件分派期间在 GUI 线程中工作的期货,并希望采用 std::future 的 API,但遇到了链接期货(非阻塞异步执行)的问题。
假设我们有一个返回未来的函数,我们想在未来准备好后执行一些事情
disconnect().then([](std::future<State> &&f)
...
);
我的理解是,当对从“then”返回的未来不做任何事情时,它将被销毁,未来将被中止,函数将不再执行。因此,为了确保链仍然存在并正确执行,我们必须将未来保存在某个地方(可能作为数据成员)。
如果我们对返回的 future 不感兴趣,而只对操作链和函数是否正确执行感兴趣,我们应该怎么做?我们是否应该把返回的future放到new std::future<R>(...)
中,完成后在lambda中删除,比如“delete &f;” ?不过,这看起来不对。
【问题讨论】:
如果未来是可选的,它可能应该是一个指针或一个 unique_ptr @paulm “如果未来是可选的”是什么意思? "then" 不总是返回一个结果成为传递函数对象的返回值的未来吗? "如果我们对返回的未来不感兴趣,我们应该怎么做" 如果你不总是想要未来,那么它应该是可选的 如果“then”不返回未来,那么计算的状态将如何存储?出于这个问题的目的,我们假设我们正在研究并发 TS 的 std::future。我如何在不存储期货的情况下触发这样的链? "我的理解是,当对"then"返回的future不做任何事情时,它将被销毁,future将被中止,函数将不再执行。" 并发的地方TS 是这么说的吗? 【参考方案1】:我不认为您需要持有future
来确保调用您的完成处理程序。销毁第二个future
不需要销毁shared_state,它只是减少它的引用计数。
一种自己实现then
的方法,来自Herb Sutter 在2012 年的C++ Concurrency 演示文稿,是调用std::async
(page 6 of the slides PDF) 的免费函数:
template<typename Fut, typename Work>
auto then( Fut f, Work w ) -> future<decltype(w(f.get()))>
return async([=] w( f.get() ); );
这占用了一个线程,但是你得到then( disconnect(), [](std::future<State> &&f) ...);
的调用者不需要阻塞的语义。即使我们丢弃了 then
调用的结果,返回的 future
也会被销毁,它的共享状态也会被清理,但您传入的 future f
不会被销毁。
然后是destroying a future
returned by async
may block until the async
completes 的规则,这意味着如果你丢弃这个then
实现的结果,你无论如何都可以阻塞(page 21)。所以你毕竟不能这样做。
在预期的效果中,then
将像将对您的函数对象的引用放入 future
的共享状态的“延续槽”中一样运行,以及第二个 promise
的返回函数对象的类型,并返回第二个promise
的future
。所以原future
的共享状态被原promise
引用,第二个future
的共享状态被第二个promise
引用,所以都不共享状态被你对第二个future
所做的任何事情摧毁。
一旦原始的promise
被满足,共享状态就会看到它已经占用了延续槽,所以刚刚满足的值中的make_ready_future
也是如此,并将其提供给您的函数对象,将值设置为第二个@ 987654353@,没有效果,因为你把第二个future
扔掉了。但是“没有影响”是对你的 lambda 的 输出。
(在实现方面,第二个future
很可能是对第二个共享状态的唯一引用,其中的promise
只是行为说明,第二个共享状态可以在不强制第一个共享状态的情况下被销毁共享状态将被销毁。我希望在内部它可以比 make_ready_future
在价值上做得更好......)
【讨论】:
这些是关于then()
如何在调用它的 future
被破坏时如何工作的非常有趣的见解。那么,是否可以保证在即将到期的未来致电then()
始终是安全的?过期是因为它只是示例中的临时对象,或者因为它会在调用完成处理程序之前超出范围。 (我希望en.cppreference.com 有关于相对寿命预期的声明)。
是的,我相信这是有保证的。 then()
与 this
未来的“旧”共享状态交互:“旧”共享状态有一个 promise
、async
或其他“异步任务”仍然保持活动状态;或者它包含将应用于“新”共享状态的值或异常,此时旧共享状态不再有趣并且将消失。 无论,this
的未来不再有趣,也不再是valid()
。
附带说明,我相信stlab::future 实现了这个问题所期望的行为,并允许没有剩余输出的打包任务future
自身不运行,滚动任务链备份到有人可能观察到输出的最后一个地方。这个版本的future
在语义上也更接近shared_future
,所以then
不会使future
对象失效。这意味着您必须坚持中间的future
s,您不想中止整个链条,而且您可以坚持下去。以上是关于并发 TS:std::future<...>::then,如何在不存储返回的未来的情况下保持链存活?的主要内容,如果未能解决你的问题,请参考以下文章
C++并发与多线程 10_shared_futureautomic
C++并发与多线程 9_asyncfuturepackaged_taskpromise