I was experiencing occasional crashes in C++/WinRT’s resume_foreground function when it tries to resume execution on a dispatcher queue. Here’s a simplified version of that function:
auto resume_foreground(DispatcherQueue const& dispatcher)
bool m_queued = false; bool await_ready()
Today is a puzzle you can you can try to solve with the information you’ve learned about C++ coroutines and C++/WinRT.
C++/WinRT uses the IContextCallback interface to remember the context that initiated a co_await operation, so it can resume execution in the original apartment when the co_await completes.
So you’re following along Kenny Kerr’s blog and you get to the part where he uses co_await on a time duration:
co_await 5s; so you try it:
using namespace std::chrono;
} and you get the error message
no callable ‘await_resume’
At the start of this series, I noted that there are three steps in obtaining an awaiter for an awaitable object. The first two were marked “We’re not read to talk about this yet.”
Well, now we’re ready to talk about one of them.
You try to co_await something and get the error message
no callable ‘await_resume’ (or ‘await_ready’ or ‘await_suspend’) function found for type ‘Expression’
What does this mean?
Recall how the compiler generates code for co_await: calculate x
obtain awaiter co_await if (!awaiter.await_ready())
save state for resumption
return to caller [Invoking the handle resumes execution here]
restore state after resumption
result = awaiter.await_resume();
There’s one last section of the outline of compiler code generation for co_await that is marked “We’re not ready to talk about this step yet.” Let’s talk about that step.
Before suspending the coroutine, the compiler asks the awaiter’s await_ready method.
At the start of this series, I gave the basic idea for how the compiler generates code for co_await, but I left out some details for expository simplicity. There are some mysterious steps called “We’re not ready to talk about this step yet.”
The C++/WinRT library provides an awaiter for Windows Runtime asynchronous activities. Those asynchronous activities are represented by IAsyncAction, IAsyncOperation, and progress versions of the above. The C++/WinRT-provided awaiter resumes execution of the caller in the same COM apartment that awaited the activity.
So far, we’ve been looking at the basics of awaitable objects. Even though we barely know anything beyond await_suspend, we already know enough to allow us to start diving deeper.
It is frequently the case that you need your awaiter to interact with something outside the C++ standard library.
Last time, we learned how to create simple awaitable objects by creating a structure that implements the await_suspend method (and relies on suspend_always to do the coroutine paperwork for us). We can then construct the awaitable object and then co_await on it.