In C#, nested await is supported like below example. The compiler will stitch the resumption of the code together (i.e. return count in method 1 will invoke int count= in outer layer and then method3 and console.ReadKey()). However I found it hard to this in c++ coroutine framework.
class Program
{
static void Main(string[] args)
{
callMethod();
Console.ReadKey();
}
public static async void callMethod()
{
Task<int> task = Method1();
Method2();
int count = await task;
Method3(count);
}
public static async Task<int> Method1()
{
int count = 0;
await Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine(" Method 1");
count += 1;
}
});
return count;
}
public static void Method2()
{
for (int i = 0; i < 25; i++)
{
Console.WriteLine(" Method 2");
}
}
public static void Method3(int count)
{
Console.WriteLine("Total count is " + count);
}
}
In C++ coroutine framework (below is my failed attempt in C++),how do I resume the code after the call to "co_await Foo2()"? It seems we need to chain the coroutine handles together problematically and calls it after the deepest co_await resume. But how to do that? Below is the output.
140717656352576 Promise created
Send back a return_type
Created a return_type object
140717656352576 Started the coroutine, don't stop now!
140717656352576 enter Foo1
140717656352576 Promise created
Send back a return_type
Created a return_type object
140717656352576 Started the coroutine, don't stop now!
140717656352576 enter Foo2
140717656352576 await_suspend
140717656352576 await_suspend in return_type
140717656352576 After Foo1
140717656348416 in Run
140717656348416 await_resume
140717656348416 resume in Foo2
140717656348416 Finished the coro --> **anyway I can call Foo1's handle to resume here?**
140717656348416 Promise died
return_type gone
Below is the code with key question on how to do nested resume in comment.
void run(std::coroutine_handle<> h)
{
std::cout<<std::this_thread::get_id()<<" "<<"in Run\n";
std::this_thread::sleep_for (std::chrono::seconds(5));
h.resume();
}
struct MyObj {
MyObj():v_(0){}
MyObj(int v):v_(v){}
int get() { return v_; }
int v_;
};
struct return_type {
return_type() {
std::cout << "Created a return_type object"<<std::endl;
}
~return_type() {
std::cout << "return_type gone" << std::endl;
}
struct promise_type {
promise_type() {
std::cout<<std::this_thread::get_id() <<" Promise created" << std::endl;
}
~promise_type() {
std::cout<<std::this_thread::get_id() << " Promise died" << std::endl;
}
auto get_return_object() {
std::cout << "Send back a return_type" <<std::endl;
return return_type();
}
auto initial_suspend() {
std::cout<<std::this_thread::get_id() <<" Started the coroutine, don't stop now!" << std::endl;
return std::suspend_never{};
}
auto final_suspend() {
std::cout<<std::this_thread::get_id() << " Finished the coro" << std::endl;
return std::suspend_never{};
}
void unhandled_exception() {
std::exit(1);
}
};
constexpr bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<promise_type> h) {
std::cout<<std::this_thread::get_id()<<" "<<"await_suspend in return_type\n";
}
void await_resume() const noexcept {
std::cout<<std::this_thread::get_id()<<" "<<"await_resume in resume_type\n";
}
};
struct Awaitable {
constexpr bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<> h)
{
std::cout<<std::this_thread::get_id()<<" "<<"await_suspend\n";
std::thread t(run, h);
t.detach();
}
void await_resume() const noexcept {
std::cout<<std::this_thread::get_id()<<" "<<"await_resume\n";
}
};
return_type Foo2()
{
std::cout<<std::this_thread::get_id()<<" "<<"enter Foo2\n";
Awaitable a;
co_await a;
std::cout<<std::this_thread::get_id()<<" "<<"resume in Foo2\n";
**// This is where promise_type::final_suspend() is called
// Naturally, I'd want to call previous (Foo1)'s handle to resume
// but I have no way of doing so.**
}
return_type Foo1()
{
std::cout<<std::this_thread::get_id()<<" "<<"enter Foo1\n";
co_await Foo2();
std::cout<<std::this_thread::get_id()<<" resume in Foo1\n";
}
int main() {
auto r = Foo1();
std::cout<<std::this_thread::get_id()<<" After Foo1 \n";;
std::this_thread::sleep_for (std::chrono::seconds(10));
}
await_suspend. You probably want to resume that coroutine infinal_suspend.h_for two different things - get() assumes it holds the coroutine being returned, butawait_suspendstores the coroutine that is awaiting.return_type'sawait_suspendmethod needs to save the parent's coroutine handle in the promise, so the promise can resume it when it hits itsfinal_suspend.