{"id":107742,"date":"2023-01-23T07:00:00","date_gmt":"2023-01-23T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107742"},"modified":"2023-01-22T17:27:00","modified_gmt":"2023-01-23T01:27:00","slug":"20230123-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230123-00\/?p=107742","title":{"rendered":"Inside C++\/WinRT: Coroutine completions: The oversimplified version"},"content":{"rendered":"<p>C++\/WinRT coroutines use the <code>Completed<\/code> delegate property to be notified when an asynchronous operation is complete. There are multiple parts of the completion handler. Today we&#8217;ll look at an oversimplified version, and then we will gradually build it up.<\/p>\n<pre>template &lt;typename Async&gt;\r\nstruct await_adapter\r\n{\r\n    await_adapter(Async const&amp; async) : async(async) { }\r\n\r\n    Async const&amp; async;\r\n\r\n    bool await_ready() const noexcept\r\n    {\r\n        return false;\r\n    }\r\n\r\n    void await_suspend(std::experimental::coroutine_handle&lt;&gt; handle) const\r\n    {\r\n        async.Completed([handle](auto&amp;&amp; ...)\r\n        {\r\n            handle.resume();\r\n        });\r\n    }\r\n\r\n    auto await_resume() const\r\n    {\r\n        return async.GetResults();\r\n    }\r\n};\r\n<\/pre>\n<p>To <code>co_await<\/code> an <code>IAsyncAction<\/code> or <code>IAsyncOperation<\/code>, we register a completion callback that resumes the awaiting coroutine. When the coroutine resumes, it will call <code>await_resume()<\/code> to obtain the result of the <code>co_await<\/code>, and we propagate the result of the <code>GetResults()<\/code> method.<\/p>\n<p>We don&#8217;t particularly care about the parameters passed to the completion delegate: Those tell us whether the asynchronous work completed successfully, was cancelled, or failed outright, but we don&#8217;t need to remember that information because <code>GetResults()<\/code> will report the information again: If the asynchronous work did not complete successfully, then <code>GetResults()<\/code> will thrown an exception describing why it was not successful.<\/p>\n<p>As things go, this is a fairly standard implementation of a coroutine awaiter, although there is a race condition we need to fix:<\/p>\n<pre>    void await_suspend(std::experimental::coroutine_handle&lt;&gt; handle) const\r\n    {\r\n        <span style=\"color: #08f;\">auto extend_lifetime = async;<\/span>\r\n        async.Completed([handle](auto&amp;&amp; ...)\r\n        {\r\n            handle.resume();\r\n        });\r\n    }\r\n<\/pre>\n<p>If the completion handler runs before <code>Completed()<\/code> returns, then we end up destroying the <code>async<\/code> while there is still an active call on it. This is a problem I called out <a title=\"C++ coroutines: Getting started with awaitable objects\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191209-00\/?p=103195\"> at the start of my coroutine series<\/a>. To fix this, we make a local copy of the <code>async<\/code> to extend its lifetime to the end of the <code>await_suspend<\/code> function.<\/p>\n<p>This is just the starting point for C++\/WinRT coroutine completion handlers. Next time, we&#8217;ll add apartment-preserving behavior.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Resuming the coroutine when the asynchronous work completes.<\/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-107742","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Resuming the coroutine when the asynchronous work completes.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107742","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=107742"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107742\/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=107742"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107742"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107742"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}