并发 TS:std::future<...>::then,如何在不存储返回的未来的情况下保持链活着?

Joh*_*itb 5 c++ future c++17

我正在构建一组在事件调度期间在 GUI 线程中工作的期货,并希望采用 std::future 的 API,但遇到了链接期货(非阻塞异步执行)的问题。

假设我们有一个返回未来的函数,我们想在未来准备好后执行一些事情

disconnect().then([](std::future<State> &&f) {
   ...
});
Run Code Online (Sandbox Code Playgroud)

我的理解是,当从“then”返回的未来不做任何事情时,它将被销毁,未来将被中止,函数将不再被执行。因此,为了确保链仍然存在并正确执行,我们必须将未来保存在某处(可能作为数据成员)。

如果我们对返回的未来不感兴趣,而只对操作链和函数正确执行感兴趣,我们该怎么办?我们是否应该将返回的 future 移入 anew std::future<R>(...)并在完成后在 lambda 中将其删除,例如“删除 &f;” ? 不过,这看起来不对。

TBB*_*Ble 2

我不认为您需要持有来future确保调用完成处理程序。销毁第二个future并不需要销毁shared_state,它只是减少其引用计数。

then一种自行实现的方法(来自 Herb Sutter 在 2012 年的C++ 并发演示)是作为一个自由函数来调用std::async幻灯片 PDF 第 6 页):

template<typename Fut, typename Work>
auto then( Fut f, Work w ) -> future<decltype(w(f.get()))>
  { return async([=]{ w( f.get() ); }); }
Run Code Online (Sandbox Code Playgroud)

then( disconnect(), [](std::future<State> &&f) {...});这会占用一个线程,但你会得到调用者不需要阻塞的语义。即使我们丢弃该then调用的结果,返回的结果future也会被破坏,并且其共享状态也会被清除,但future f您传入的内容不会被破坏。

然后有一条规则,即销毁future由返回的对象async可能会阻塞,直到async完成为止,这意味着如果您丢弃此then实现的结果,则无论如何都可能会阻塞(第21页)。所以你终究不能这么做。

在期望的效果中,then将进行操作,就好像它将对函数对象的引用放入 的共享状态的“连续槽”中future,以及promise函数对象的第二个返回类型,并返回该函数future对象的第二promise。因此,原始状态future的共享状态由原始状态引用promise,而第二个future状态的共享状态由第二个状态引用promise,因此无论您对第二个状态执行什么操作,都不会破坏这两个共享状态future

一旦原始状态promise被满足,共享状态就会发现它已占用了延续槽,因此 a 会make_ready_future从刚刚满足的值中取出并将其提供给您的函数对象,并将该值设置为第二个promise,这没有任何效果,因为您抛出了第二个future离开。但“没有影响”是在lambda 的输出上。

(在实现方面,第二个future很可能是对第二个共享状态的唯一引用,其中promise只是一个行为说明,可以在不强制销毁第一个共享状态的情况下销毁第二个共享状态。我希望在内部它可以做得比make_ready_future价值更好......)