I am studying about coroutines and symmetric transfer. Based on https://itnext.io/c-20-practical-coroutines-79202872ebba, I am trying to create a simple example where a coroutine bar waiting coroutine foo to return before returns its result. However the body of function bar is never called. Below is my try
#include <iostream>
#include <coroutine>
#include <coroutine>
#include <exception>
#include <utility>
// Chainable task for awaitable coroutines.
struct Task {
struct Promise {
using handle_t = std::coroutine_handle<Promise>;
Task get_return_object() {
return Task{handle_t::from_promise(*this)};
}
std::suspend_always initial_suspend() noexcept {
std::cout << "initial suspend_always" << std::endl;
return {};
}
std::suspend_always final_suspend() noexcept {
std::cout << "final suspend_always" << std::endl;
return {};
}
void unhandled_exception() {
std::cout << "exception" << std::endl;
std::terminate();
}
void return_value(int result) { result_ = result; }
//void return_void(void){}
private:
std::coroutine_handle<> continuation = std::noop_coroutine();
int result_;
friend struct Task;
};
using promise_type = Promise;
explicit Task(promise_type::handle_t handle) : handle_(handle) {}
Task(const Task &) = delete;
Task(Task &&task)
: handle_(std::exchange(task.handle_, nullptr)) {}
Task &operator=(const Task &) = delete;
Task &operator=(Task &&task) {
handle_ = std::exchange(task.handle_, nullptr);
return *this;
}
~Task() {
if (handle_)
handle_.destroy();
}
bool await_ready() noexcept { return false; }
std::coroutine_handle<> await_suspend(std::coroutine_handle<> caller) {
std::cout << "await_suspend" << std::endl;
handle_.promise().continuation = caller;
std::cout << "suspend" << std::endl;
return std::noop_coroutine();
}
auto await_resume() {
std::cout << "resume" << std::endl;
return handle_.promise().result_; }
private:
promise_type::handle_t handle_;
};
Task foo(){
std::cout << "foo" << std::endl;
co_return 2;
}
Task bar(){
std::cout << "bar" << std::endl;
auto result = co_await foo();
std::cout << "return from foo" << std::endl;
co_return result;
}
int main(int argc, const char * argv[]) {
Task c = bar();
std::cout << "return from bar" << std::endl;
int i = 0;
c.await_resume();
//c.await_resume();
while(1){}
std::cout << "Hello, World!\n" <<std::endl;
return 0;
}
Code under https://godbolt.org/z/evoGG4d43 Any help to this?
When you call
bar, it hits its initial suspend point, as you can see from the output. Then, you seem to think that callingc.await_resume()resumes the coroutine, but in fact it does no such thing;c.await_resume()is simply an ordinary function call, where the fact that the function is namedawait_resumedoes not magically cause it to resume the coroutine. (Rather,await_resumeis called automatically by aco_awaitexpression after the calling coroutine is resumed.)To resume the suspended invocation of
barfrom another coroutine, you would normally useco_await c. But sincemainisn't a coroutine, you instead need to find some way of getting the coroutine handle that refers to that coroutine frame (which is not possible in your current implementation becausehandle_is private) or call some public member ofTaskthat tells it to resume itself (which also doesn't exist in your current implementation). Or implement a different coroutine thatco_awaits oncfor you, and make that coroutine run to completion.For example, in your Godbolt snippet, if we make
handle_public and then callc.handle_.resume()twice instead ofc.await_resume(), I think you get the behaviour that you're looking for.