C++/WinRT asynchronous activities can be awaited only once. This is consistent with their intended usage pattern, which is for an application to start the activity, co_await
the result, and then continue.
But maybe you want something like a Win32 event, where any number of people can co_await
the event, and then once it is signaled, all the awaiters are resumed.
Well, an easy way to do this is simply to have a Win32 event!
struct awaitable_event { void set() const noexcept { SetEvent(os_handle()); } auto operator co_await() const noexcept { return winrt::resume_on_signal(os_handle()); } private: HANDLE os_handle() const noexcept { return handle.get(); } winrt::handle handle{ winrt::check_pointer(CreateEvent(nullptr, /* manual reset */ true, /* initial state */ false, nullptr)) }; };
This class is just a wrapper around a Win32 manual-reset event handler. You can call the set
method to set the event, and you can co_await
it to wait for the event.
The traditional way of supporting co_await
is to implement the trio of methods await_
, await_
, and await_
. But another way is to define the co_await
operator so it returns an awaiter. We implement our custom co_await
operator by propagating the awaiter returned by resume_
. Basically, awaiting the awaitable_
is the same as awaiting a call of resume_
with the hidden handle.
For simple scenarios, this might be all you need. You can define a global awaitable_
and have as many people as you like co_await
it.
If you want the object not to have static storage duration (say, because it’s a member of another class which is dynamically-allocated), then you will encounter lifetime issues because you can’t destruct the awaitable_
while somebody else is still awaiting it.
We’ll continue investigating this issue next time.
0 comments