I want to know a method to pass values from the caller to the coroutine.
My idea:
Any awaiter type must provide a await_resume()
function. This function can return something to the co_await
inside the coroutine.
Is it possible to set the value inside the awaiter to transport data to the coroutine? The question in this case is: How we can get the awaiter object inside the caller?
Example:
#include <coroutine>
#include <iostream>
struct ReturnObject {
struct promise_type {
unsigned value_;
ReturnObject get_return_object()
{
return ReturnObject
{
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> h_;
operator std::coroutine_handle<promise_type>() const { return h_; }
};
struct MyAwaiter
{
bool suspend;
bool await_ready() const noexcept { return suspend; }
void await_suspend( std::coroutine_handle<> ) const noexcept { std::cout << "My awaiter suspend" << std::endl;}
std::string await_resume() const noexcept { std::cout << "My awaiter resume" << std::endl; return "Test!";}
};
ReturnObject
counter()
{
for (unsigned i = 0;; ++i)
{
std::cout << "i: " << i << std::endl;
std::string ret = co_await MyAwaiter{false};
std::cout << "Ret: " << ret << std::endl;
}
}
int main()
{
std::coroutine_handle<ReturnObject::promise_type> h = counter();
ReturnObject::promise_type &promise = h.promise();
for (int i = 0; i < 3; ++i)
{
std::cout << "Next iteration" << std::endl;
h();
/// how we can get the awaiter object here??? If we can get it, we can modify
/// it to pass data to the coroutine. Is this possible?
}
h.destroy();
}
Maybe I am totally wrong and there is any other way to pass data from the caller to the coroutine. If so: Please give me a hint and in best case a minimal working example.
await_suspend
accepts a std::coroutine_handle<void>
which you can overload to match std::coroutine_handle<ReturnObject::promise_type>
and it will be called if it is awaited by that promise_type
, and handle.promise()
will give you access to the promise.
void await_suspend( std::coroutine_handle<ReturnObject::promise_type> h) noexcept {
std::cout << "My awaiter suspend on ReturnObject" << std::endl;
h.promise().awaiter = this; // new member in promise_type
}
then in the caller you can get this information from the promise and modify the awaiter.
h.promise().awaiter->data = "foo";
Both the awaiter and the return object have access to the promise_type
, which should be used to store the relevant information, like why the coroutine was suspended, and what it is waiting on, so the caller can respond to the awaiter.
full example
#include <coroutine>
#include <iostream>
struct MyAwaiter;
struct ReturnObject {
struct promise_type {
unsigned value_;
ReturnObject get_return_object()
{
return ReturnObject
{
.h_ = std::coroutine_handle<promise_type>::from_promise(*this)
};
}
MyAwaiter* awaiter = nullptr;
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> h_;
operator std::coroutine_handle<promise_type>() const { return h_; }
};
struct MyAwaiter
{
bool suspend;
bool await_ready() const noexcept { return suspend; }
void await_suspend( std::coroutine_handle<ReturnObject::promise_type> h) noexcept {
std::cout << "My awaiter suspend on ReturnObject" << std::endl;
h.promise().awaiter = this;
}
void await_suspend( std::coroutine_handle<> ) const noexcept { std::cout << "My awaiter suspend" << std::endl;}
std::string data;
std::string await_resume() const noexcept { std::cout << "My awaiter resume" << std::endl; return data;}
};
ReturnObject
counter()
{
for (unsigned i = 0;; ++i)
{
std::cout << "i: " << i << std::endl;
std::string ret = co_await MyAwaiter{false};
std::cout << "Ret: " << ret << std::endl;
}
}
int main()
{
std::coroutine_handle<ReturnObject::promise_type> h = counter();
ReturnObject::promise_type &promise = h.promise();
for (int i = 0; i < 3; ++i)
{
std::cout << "Next iteration" << std::endl;
h.promise().awaiter->data = "foo";
h();
}
h.destroy();
}