{"id":109256,"date":"2024-01-10T07:00:00","date_gmt":"2024-01-10T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109256"},"modified":"2024-01-10T06:34:23","modified_gmt":"2024-01-10T14:34:23","slug":"20240110-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240110-00\/?p=109256","title":{"rendered":"In C++\/WinRT, how can I await multiple coroutines and capture the results?, part 1"},"content":{"rendered":"<p>The <code>winrt::<wbr \/>when_all<\/code> function in C++\/WinRT is not a complicated beast. It just awaits each of its parameters. Some time ago, <a title=\"Synthesizing a when_all coroutine from pieces you already have\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200902-00\/?p=104155\"> we looked at how it works and how you could use it to await all the coroutines in a container or range<\/a>. But all of those examples just throw away the results. What if we also want to gather the results?<\/p>\n<p>Here&#8217;s what doesn&#8217;t work:<\/p>\n<pre>auto op1 = DoSomething1Async();\r\nauto op2 = DoSomething2Async();\r\n\r\nco_await winrt::when_all(op1, op2);\r\n\r\n\/\/ These don't return proper results.\r\nauto result1 = op1.GetResults();\r\nauto result2 = op2.GetResults();\r\n<\/pre>\n<p>The problem is that the <code>co_await<\/code> inside <code>when_all<\/code> calls <code>GetResults()<\/code> in order to produce the result of the <code>co_await<\/code>. And <code>GetResults()<\/code> produces valid results only the first time it is called after completion.<\/p>\n<p>One way to solve this problem is to use a different awaiter whose <code>await_resume()<\/code> doesn&#8217;t call <code>GetResults()<\/code>, leave it to the caller to fetch the results when they are ready.<\/p>\n<pre>template&lt;typename Async&gt;\r\nstruct simple_async_awaiter\r\n{\r\n    simple_async_awaiter(Async const&amp; async) : async(async) {}\r\n\r\n    Async const&amp; async;\r\n\r\n    bool await_ready() const noexcept { return false; }\r\n\r\n    void await_suspend(std::coroutine_handle&lt;&gt; handle) const {\r\n        async.Completed([handle](auto&amp;&amp;...) { handle(); });\r\n    }\r\n\r\n    void await_resume() const noexcept {\r\n        <span style=\"border: dashed 1px currentcolor;\">\/* <span style=\"text-decoration: line-through;\">return async.GetResults();<\/span> *\/<\/span>\r\n    }\r\n};\r\n<\/pre>\n<p>We return <code>void<\/code> from <code>await_resume()<\/code>, which means that <code>co_await<\/code> returns <code>void<\/code>, and you can then fetch the results by calling <code>GetResults()<\/code>. (We also don&#8217;t bother preserving the COM apartment context, and we don&#8217;t propagate cancellation, but the point here was to show that we skipped the <code>GetResults()<\/code> inside <code>await_resume()<\/code>.)<\/p>\n<p>But this is an awful lot of work, particularly because you have to replicate <a title=\"Inside C++\/WinRT: Coroutine completions: The oversimplified version\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230123-00\/?p=107742\"> all of the stuff that C++\/WinRT does behind the scenes in its awaiter<\/a>. Maybe we can find something simpler.<\/p>\n<p>We&#8217;ll continue our exploration next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using a custom awaiter to suppress the <CODE>GetResults()<\/CODE>.<\/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-109256","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Using a custom awaiter to suppress the <CODE>GetResults()<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109256","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=109256"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109256\/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=109256"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109256"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109256"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}