Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

求助 #4

Open
uuuuu-diwu opened this issue Apr 3, 2024 · 7 comments
Open

求助 #4

uuuuu-diwu opened this issue Apr 3, 2024 · 7 comments

Comments

@uuuuu-diwu
Copy link

uuuuu-diwu commented Apr 3, 2024

我在 steps3.cpp 中将 40 行的 return PreviousAwaiter(mPrevious); 修改成了 return std::suspend_always(); 结果发现

world 协程 co_return 后没有返回到 hello 协成中的 co_await word() 处,按理 world 协成 co_return 完后应该会将控制权交还给之前 co_await 它的协成,求帮瞅瞅这里如何理解

auto final_suspend() noexcept {
// return PreviousAwaiter(mPrevious);
printf("%p exe final_suspend\n",std::coroutine_handle::from_promise(*this).address());
return std::suspend_always();
}

@archibate
Copy link
Owner

co_await并没有“返回”的功能,一个协程结束后,要切换到哪个协程(相当于返回地址)是由final_suspend().await_suspend()的协程句柄决定的。
std::suspend_always()的await_suspend()这个成员函数,返回类型void,表示不返回到任何地方,直接结束当前协程,返回到调用了world.resume()的main函数里去。
PreviousAwaiter(mPrevious)的await_suspend(),返回类型是协程句柄std::coroutine_handle<>,表示返回到这个句柄指向的协程。PreviousAwaiter的await_suspend()固定返回mPrevious,而mPrevious刚好是刚才调用world时保存的调用者hello的协程句柄,所以才能返回到hello中,而不是直接退到main里。

题外话,如果你要final_suspend()返回std::suspend_always()还能继续返回到hello里的话,main就要这样写:

int main() {
  world.resume();
  hello.resume(); // world.resume() 遇到 std::suspend_always() 被退出了,需要main函数负责手动切换回调用者hello
}

@uuuuu-diwu
Copy link
Author

"接结束当前协程,返回到调用了world.resume()的main函数里去。" 这个里面返回到调用了 world.resume() 的地方去我知道,但是为啥是 main 函数中,我看main里面调用的是hello.resume

@archibate
Copy link
Owner

说错了,是hello.resume。

@uuuuu-diwu
Copy link
Author

对,我就是想问为啥会直接从 word 里面跳转到 hello.resume 而不是 hello 内部执行

@archibate
Copy link
Owner

return PreviousAwaiter(mPrevious)
等价于
mPrevious.resume()
而mPrevious是hello

@archibate
Copy link
Owner

为什么要用return PreviousAwaiter(mPrevious)而不是mPrevious.resume()?
因为后者会爆栈,因此C++提供了一种保证堆栈不会随着一次次返回越来越高的方法,那就是允许你返回一个你要resume的协程,让编译器在当前函数退出后,自动调用你返回的协程,称之为对称转移。
如果不考虑爆栈问题,你完全可以写mPrevious.resume(),然后只是返回void,这样更直观。
https://lewissbaker.github.io/2020/05/11/understanding_symmetric_transfer

@CrossroadW
Copy link

co_await并没有“返回”的功能,一个协程结束后,要切换到哪个协程(相当于返回地址)是由final_suspend().await_suspend()的协程句柄决定的。 std::suspend_always()的await_suspend()这个成员函数,返回类型void,表示不返回到任何地方,直接结束当前协程,返回到调用了world.resume()的main函数里去。 PreviousAwaiter(mPrevious)的await_suspend(),返回类型是协程句柄std::coroutine_handle<>,表示返回到这个句柄指向的协程。PreviousAwaiter的await_suspend()固定返回mPrevious,而mPrevious刚好是刚才调用world时保存的调用者hello的协程句柄,所以才能返回到hello中,而不是直接退到main里。

题外话,如果你要final_suspend()返回std::suspend_always()还能继续返回到hello里的话,main就要这样写:

int main() {
  world.resume();
  hello.resume(); // world.resume() 遇到 std::suspend_always() 被退出了,需要main函数负责手动切换回调用者hello
}

也就是说编译器帮你resume 不算resume,只有手动resume 才算挂起点,所以返回最初的main里😘

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants