下面的代码不像我期望的那样工作。
#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_await symmetic_awaitable(co_list[i])替换为co_list[i].resume。这个排气管很奇怪
fa1
fb1
fc1
fb1
fc1
..... // the following is infinite loop of "fb1 fc1"
.....
.....C++20协同工作隐藏了太多的细节,除非我清楚地了解它们,否则代码就不能像我期望的那样正常工作。
以下是我在阅读cppreference后提出的问题:
1.“来电者”和“简历”的区别是什么?
一个呼叫b.resume(),那么a是b的简历还是调用者?
2.“暂停”的确切含义是什么?
一个呼叫b.resume(),然后一个是挂起还是正在运行?一份简历b通过co_await,然后a被挂起还是运行?
发布于 2022-06-05 03:47:03
如果一个函数是一个协同线,它只能以下列方式之一被挂起:
co_await表达式(或等效的,如co_yield)被直接调用;co_returns时,如果承诺最终中止。G 210
其他任何东西都不能使一条协同线被暂停。"coroutine“中的"co”代表合作多任务处理。这意味着,除非涉及的功能合作,否则不存在多任务处理。明文规定。
您对代码工作方式的假设似乎表明,您认为协同机制具有某种执行堆栈。当调用await_suspend时,当前协同线将被放入堆栈中,当返回的协同线句柄以某种方式结束时,堆栈将被弹出。因此,当您调用co_await std::suspend_always{};时,这将恢复以前挂起的协同线。
所有这些都不是真的。除非你自己制造那台机器。
协同系统只做你让它做的事。
调用a.resume()后的调用堆栈如下所示:
main()
fa()当fa挂起并恢复fb时,现在看起来如下所示:
main()
fb()fa走了。你把它暂停了。它不再在调用堆栈上。只有当你明确要求恢复它时,它才会被恢复。
如果你想让fa暂停进入fb意味着fa在fb完成后还会继续,那么你必须在你的协同机制中安装它。它不仅仅发生,你有责任让它发生。
您的await_suspend代码需要获得给定的句柄(它指的是fa),并将其存储在一个地方,当fb完成时,它可以恢复fa。这通常在fb的承诺对象中,这样final_suspend就可以恢复它(通常是传递由fb生成的数据)。记住:无论承诺的final_suspend返回什么,最后的挂起点都将co_await,所以您可以返回您想要恢复的协同线的句柄。
“来电者”和“简历”的区别是什么?
我不知道那是什么意思。我怀疑您是在问co_await在某件事情上的作用与直接调用coroutine_handle::resume函数之间的区别。
如前所述,在初始和最终挂起点之外,只有co_await (或等效的)表达式才能导致协同线挂起。调用句柄上的resume就像调用函数的中间一样。它就像任何其他函数调用一样工作;它进入堆栈,依此类推。
拥有co_await简历是不同的。当await_suspend返回一个协同线句柄时,这将用调用堆栈上恢复的协同线替换您的协同线。这就是暂停合作线的全部意义。
https://stackoverflow.com/questions/72504525
复制相似问题