【发布时间】:2021-07-22 15:08:52
【问题描述】:
我正在学习 c++ 20 协程。有些事情还不清楚,尽管我已经看过几个关于这个话题的视频。
我正在尝试获得一个可组合的协程。我已经了解了这样做的对称传输,这是我的代码(请原谅长示例):
#include <coroutine>
#include <iostream>
// forward declaration
template <class T> struct promise;
// simple wrapper to follow the workflow
struct MySuspendAlways
{ // (1)
bool await_ready() const noexcept {
std::cout << "\tMySuspendAlways::await_ready" << '\n';
return false;
}
bool await_suspend(std::coroutine_handle<> handle) const noexcept {
std::cout << "\tMySuspendAlways::await_suspend coro handle " << handle.address() << '\n';
return true;
}
void await_resume() const noexcept {
std::cout << "\tMySuspendAlways::await_resume" << '\n';
}
};
template < typename T>
struct SimpleAwaitable
{
std::coroutine_handle<promise<T>> coro_;
SimpleAwaitable(std::coroutine_handle<promise<T>> coro) :
coro_{ coro }
{
std::cout << "\n\tSimpleAwaitable::coro handle = " << coro_.address();
}
bool await_ready()
{
std::cout << "\n\tSimpleAwaitable::await_ready coro handle " << coro_.address();
if (!coro_.done())
{
return false;
}
return true;
}
std::coroutine_handle<> await_suspend(std::coroutine_handle<> continuationCoro)
{
std::cout << "\n\tSimpleAwaitable::await_suspend coro handle " << coro_.address();
coro_.promise().set_continuation(continuationCoro);
return coro_;
}
decltype(auto) await_resume()
{
std::cout << "\n\tSimpleAwaitable::await_resume coro handle " << coro_.address();
return coro_.promise().value_;
}
};
struct final_awaitable
{
bool await_ready() noexcept { return false; };
void await_resume() noexcept {}
template < typename P>
std::coroutine_handle<> await_suspend(std::coroutine_handle<P> finalizedCoro) noexcept
{
auto& continuation = finalizedCoro.promise().continuation_;
return continuation ? continuation : std::noop_coroutine();
}
};
// promise type
template <typename T>
struct promise
{
T value_;
std::coroutine_handle<> continuation_;
auto get_return_object() noexcept
{
return std::coroutine_handle<promise>::from_promise(*this);
}
MySuspendAlways initial_suspend() noexcept
{
std::cout << "\t|_Job prepared" << '\n';
return {};
}
final_awaitable final_suspend() noexcept {
std::cout << "\t|_Job finished" << '\n';
return {};
}
void unhandled_exception() noexcept
{
std::terminate();
}
void return_value(T t) noexcept { value_ = std::move(t); }
void set_continuation(std::coroutine_handle<> continuation) noexcept
{
std::cout << "\tset chain with coro hadle = " << continuation.address() << '\n';
continuation_ = continuation;
}
auto continuation() noexcept
{
return continuation_;
}
};
template < typename T>
class task_
{
public:
using promise_type = promise<T>;
task_(std::coroutine_handle<promise_type> handle) :
handle_(handle)
{}
~task_()
{
if (handle_)
{
std::cout << "\n\t\tDestoy " << handle_.address();
handle_.destroy();
}
}
T value() noexcept { return handle_.promise().value_; }
void resume() noexcept
{
if (!handle_.done())
{
handle_.resume();
}
}
bool is_ready() noexcept { return handle_.done(); }
auto operator co_await() const noexcept
{
std::cout << "\n\tCO_AWAIT\n";
return SimpleAwaitable<T>{handle_};
}
private:
std::coroutine_handle<promise<T>> handle_;
};
task_<std::string> suspending_2()
{
std::cout << "\n[, ]";
co_await std::suspend_always{};
std::cout << "\n[WORLD]";
co_return "done";
}
task_<std::string> composed_2()
{
std::cout << "\n[HELLO]";
co_await suspending_2();
std::cout << "\n[!!]";
co_return "end";
}
int main() {
task_<std::string> x = composed_2();
while (!x.is_ready())
{
std::cout << "\nresuming...";
x.resume();
}
return 0;
}
我期望这个流程:
你好 -> ,_ -> 世界 -> !!
但我得到的是:
你好 -> ,_ , -> !!
尽管我仔细阅读了有关最终等待者、继续句柄、await_suspend 返回的恢复继续的 coro 句柄,但它不起作用。
有没有协程专家解释我哪里错了?
谢谢
【问题讨论】: