C ++ 20协程:实现可期待的未来

时间:2019-03-09 23:20:00

标签: c++ async-await future c++20 c++-coroutine

自从Coroutines TS在科纳(Kona)的ISO会议上被C ++ 20接受后,我就开始为他们自己玩一些。 Clang已经对协程提供了不错的支持,但是仍然缺乏库支持的实现。特别是,尚未实现 Awaitable 类型,例如std::futurestd::generator等。

因此,我自己承担起std::future的等待。我在很大程度上遵循了talk by James McNellis at CppCon 2016,尤其是这张幻灯片:

Screengrab at timestamp 37:41 of James McNellis talk at CppCon 2016

现在是2019年,我实际上对这张幻灯片上的(可能未经测试?)代码遇到了麻烦:

  • 在我看来,operator co_await过载已不是问题了吗?相反,应该使用await_transform中的可选promise_type。不过,我不确定我是否正确。
  • 将来的then继续按值捕获句柄,但是resume成员函数不是const限定的。我通过制作lambda mutable来解决此问题。

此外,then中没有is_readystd::future,但它们是std::experimental::future的一部分,而我的libc ++版本中仍然缺少它们。为了避免与Awaiter打交道并实现将来的延续,我编写了派生的Future类,它是Awaitable和Awaiter。据我了解,std::future最终都将适用。您可以看到我的example on Compiler Explorer。它执行编译。

但是,它也确实存在段错误。在调用await_resume时,这会在get()中发生。实际上,这并不奇怪,因为valid()会在此时返回false(调用get() UB)。我认为这是因为当使用then来延续未来时,原始的Future对象被移入了异步的Future中,从而使旧的Future失效(在*this时被称为await_resume ,因此在移动之后)。我在GitHub上找到的this answerthis code启发了then的实现。这些可能并不理想,但是将cppreference explicitly states valid() == false作为调用then的后置条件,所以我认为摆脱原来的未来是正确的。

我在这里想念什么?上面的幻灯片中似乎已经存在该“错误”。我该如何调和这个问题?有人知道等待的未来的(有效的)现有实现吗?谢谢。

1 个答案:

答案 0 :(得分:1)

您曾经提到自己,问题是因为future在调用.then()之后已经移出。诀窍是在准备就绪时将其移回。如果传递给.then()的延续采用future,而不是它所拥有的值,则可以完成此操作。

这是我从您的代码中获取并更改的功能。我也将它们从传递参数到std::async改为捕获它们,因为对我来说这看起来更直观,但这不是重要的更改。

    template <typename Work>
    auto then(Work&& w) -> co_future<decltype(w())> {
        return { std::async([fut = std::move(*this), w = std::forward<Work>(w)]() mutable {
            fut.wait();
            return w();
        })};
    }

    template <typename Work>
    auto then(Work&& w) -> co_future<decltype(w(std::move(*this)))> {
        return { std::async([fut = std::move(*this), w = std::forward<Work>(w)]() mutable {
            return w(std::move(fut));
        })};
    }

    void await_suspend(std::experimental::coroutine_handle<> ch) {
        then([ch, this](auto fut) mutable {
            *this = std::move(fut);
            ch.resume();
        });
    }

顺便说一句,VS2017抱怨在承诺类型中同时包含set_exception()unhandled_exception()。我删除了set_exception()并将unhandled_exception()更改为此:

    void unhandled_exception() {
        _promise.set_exception(std::current_exception());
    }