{"id":104914,"date":"2021-03-01T07:00:00","date_gmt":"2021-03-01T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=104914"},"modified":"2021-03-02T06:41:29","modified_gmt":"2021-03-02T14:41:29","slug":"20210301-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210301-00\/?p=104914","title":{"rendered":"Creating a co_await awaitable signal that can be awaited multiple times, part 1"},"content":{"rendered":"<p><a title=\"What does error E_ILLEGAL_DELEGATE_ASSIGNMENT mean?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210226-00\/?p=104911\"> C++\/WinRT asynchronous activities can be awaited only once<\/a>. This is consistent with their intended usage pattern, which is for an application to start the activity, <code>co_await<\/code> the result, and then continue.<\/p>\n<p>But maybe you want something like a Win32 event, where any number of people can <code>co_await<\/code> the event, and then once it is signaled, all the awaiters are resumed.<\/p>\n<p>Well, an easy way to do this is simply to have a Win32 event!<\/p>\n<pre>struct awaitable_event\r\n{\r\n  void set() const noexcept\r\n  { SetEvent(os_handle()); }\r\n\r\n  auto operator co_await() const noexcept\r\n  { return winrt::resume_on_signal(os_handle()); }\r\n\r\nprivate:\r\n  HANDLE os_handle() const noexcept\r\n  { return handle.get(); }\r\n\r\n  winrt::handle handle{\r\n    winrt::check_pointer(CreateEvent(nullptr,\r\n      \/* manual reset *\/ true, \/* initial state *\/ false,\r\n      nullptr)) };\r\n};\r\n<\/pre>\n<p>This class is just a wrapper around a Win32 manual-reset event handler. You can call the <code>set<\/code> method to set the event, and you can <code>co_await<\/code> it to wait for the event.<\/p>\n<p>The traditional way of supporting <code>co_await<\/code> is to implement the trio of methods <code>await_<wbr \/>ready<\/code>, <code>await_<wbr \/>suspend<\/code>, and <code>await_<wbr \/>resume<\/code>. But another way is to <a title=\"C++ coroutines: Defining the co_await operator\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191218-00\/?p=103221\"> define the <code>co_await<\/code> operator<\/a> so it returns an awaiter. We implement our custom <code>co_await<\/code> operator by propagating the awaiter returned by <code>resume_<wbr \/>on_<wbr \/>signal<\/code>. Basically, awaiting the <code>awaitable_<wbr \/>event<\/code> is the same as awaiting a call of <code>resume_<wbr \/>on_<wbr \/>signal<\/code> with the hidden handle.<\/p>\n<p>For simple scenarios, this might be all you need. You can define a global <code>awaitable_<wbr \/>event<\/code> and have as many people as you like <code>co_await<\/code> it.<\/p>\n<p>If you want the object not to have static storage duration (say, because it&#8217;s a member of another class which is dynamically-allocated), then you will encounter lifetime issues because you can&#8217;t destruct the <code>awaitable_<wbr \/>event<\/code> while somebody else is still awaiting it.<\/p>\n<p>We&#8217;ll continue investigating this issue <a title=\"Creating a co_await awaitable signal that can be awaited multiple times, part 2\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210302-00\/?p=104918\"> next time<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sort of like an event.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-104914","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Sort of like an event.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104914","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=104914"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/104914\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=104914"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=104914"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=104914"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}