"co_await other_co"和"other_co.resume"有什么区别?



下面的代码没有达到我的预期。

#include <iostream>
#include <coroutine>
#include <vector>
struct symmetic_awaitable
{
std::coroutine_handle<> _next_h;
symmetic_awaitable(std::coroutine_handle<> h) : _next_h(h) {}
constexpr bool await_ready() const noexcept { return false; }
std::coroutine_handle<> await_suspend(std::coroutine_handle<>) const noexcept
{
return _next_h;
}
constexpr void await_resume() const noexcept {}
};
struct return_object : std::coroutine_handle<>
{
struct promise_type
{
return_object get_return_object()
{
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
return_object(std::coroutine_handle<promise_type> h) : std::coroutine_handle<>(h) {}
};
std::vector<return_object> co_list;
return_object fa()
{
std::cout << "fa1" << std::endl;
co_await symmetic_awaitable(co_list[1]);
std::cout << "fa2" << std::endl;
co_return;
}
return_object fb()
{
std::cout << "fb1" << std::endl;
co_await symmetic_awaitable(co_list[2]);
std::cout << "fb2" << std::endl;
co_await std::suspend_always{};
std::cout << "fb3" << std::endl;
co_return;
}
return_object fc()
{
std::cout << "fc1" << std::endl;
co_await symmetic_awaitable(co_list[1]);
std::cout << "fc2" << std::endl;
co_return;
}
int main()
{
auto a = fa();
auto b = fb();
auto c = fc();
co_list.push_back(a);
co_list.push_back(b);
co_list.push_back(c);
a.resume();
std::cout << "end" << std::endl;
a.destroy();
b.destroy();
c.destroy();
}

我认为输出将是

fa1
fb1
fc1
fb2
fa2
end

但实际输出是

fa1
fb1
fc1
fb2
end

然后我用co_list[i].resume替换所有的co_await symmetic_awaitable(co_list[i])。输出很奇怪

fa1
fb1
fc1
fb1
fc1
.....  // the following is infinite loop of "fb1 fc1"
.....
.....

c++ 20协程隐藏了太多的细节,以至于代码不能像我期望的那样正常工作,除非我清楚地知道它们。
阅读cppreference后,我的问题如下:

1。"caller"one_answers"caller"有什么区别?和";resumer"?

a调用b.resume(),则a是b的接收方还是调用方?

2。"暂停"的确切含义是什么??

a呼叫b.resume(),则a挂起或正在运行?a通过co_await恢复b,则a挂起或正在运行?

如果一个函数是协程,它只能以下列方式之一挂起:

  1. 协程启动时,如果promise最初挂起。
  2. 当直接调用co_await表达式(或等价的,如co_yield)时。
  3. 当协程co_returns时,如果promise最终挂起。

没有其他可以导致协程挂起。"co"在"coroutine"代表合作多任务。这意味着没有多任务处理,除非涉及的函数合作。明确。

你对你期望代码如何工作的假设似乎表明你相信协程有某种执行堆栈。当await_suspend被调用时,当前的协程被放到一个堆栈中,当你返回的协程句柄以某种方式完成时,这个堆栈将被弹出。因此,当您调用co_await std::suspend_always{};时,这将恢复先前挂起的协程。

这些都不是真的。除非你自己制造机器。

协程系统只做你让它做的事情。

调用a.resume()后立即调用堆栈如下所示:

main()
fa()

fa挂起并恢复fb时,现在看起来像这样:

main()
fb()

faisgone。你暂停了它。它不再位于调用堆栈上。只有当你明确地请求恢复时,它才会被恢复。

如果你想让fa的暂停进入fb意味着fa将在fb结束后继续运行,那么你必须构建到你的协同程序机器中。这不是偶然发生的;你有责任去实现它。

您的await_suspend代码需要接受它给出的句柄(指fa)并将其存储在一个地方,当fb完成时,它可以恢复fa。这通常会在fb的promise对象中,这样final_suspend就可以恢复它(通常会传递fb生成的数据)。请记住:无论promise的final_suspend返回什么,最终挂起点都将返回co_await,因此您可以只返回想要恢复的协程的句柄。

caller"有什么区别?和";resumer">

?
我不知道那是什么意思。我怀疑你是在问co_await和直接调用coroutine_handle::resume函数之间的区别是什么。

如前所述,在初始和最终挂起点之外,只有co_await(或等价的)表达式可以导致协程挂起。在句柄上调用resume就像在函数的中间调用一样。它就像任何其他函数调用一样工作;它进入堆栈,等等

co_await恢复协程是不同的。当await_suspend返回一个协程句柄时,这个用调用堆栈上恢复的协程替换您的协程。这就是挂起协程的意义所在。

最新更新