{"id":107175,"date":"2022-09-14T07:00:00","date_gmt":"2022-09-14T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107175"},"modified":"2022-09-14T07:41:30","modified_gmt":"2022-09-14T14:41:30","slug":"20220914-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220914-00\/?p=107175","title":{"rendered":"Creating a lazy-start C++\/WinRT coroutine from an eager-start one, part 2"},"content":{"rendered":"<p>Last time, we created a lazy-start C++\/WinRT coroutine wrapper around a standard <code>IAsyncAction<\/code> or <code>IAsyncOperation<\/code>, which is an eager-start coroutine. We did it by sharing a kernel handle with the coroutine and having the coroutine wait for the handle to be signaled before beginning its work.<\/p>\n<p>But we can do better, if we are willing to dig down a little bit.<\/p>\n<p>The trick here is to have the coroutine suspend itself, and then manually resume it.<\/p>\n<pre>template&lt;typename Make&gt;\r\nauto MakeLazy(Make make) -&gt; decltype(make())\r\n{\r\n    <span style=\"color: blue;\">struct suspender\r\n    {\r\n        void resume() { handle(); }\r\n\r\n        bool await_ready() { return false; }\r\n        void await_suspend(std::experimental::coroutine_handle&lt;&gt; h)\r\n        { handle = h; }\r\n        void await_resume() { }\r\n    private:\r\n        std::experimental::coroutine_handle&lt;&gt; handle;\r\n    };\r\n\r\n    suspender suspend;<\/span>\r\n    auto currentTask = [](auto start, auto make, <span style=\"color: blue;\">auto&amp; suspend<\/span>)\r\n        -&gt; decltype(make()) {\r\n        <span style=\"color: blue;\">co_await suspend;<\/span>\r\n        co_return co_await make();\r\n    }(std::move(start), std::move(make), <span style=\"color: blue;\">suspend<\/span>);\r\n\r\n    \/\/ Resume the coroutine\r\n    <span style=\"color: blue;\">suspender.resume();<\/span>\r\n    return currentTask;\r\n}\r\n<\/pre>\n<p>The idea here is to create a custom awaitable object which saves the coroutine handle, which can be resumed by an explicit call to the <code>resume()<\/code> method.<\/p>\n<p>Recall that what makes a C++ coroutine lazy-start is that it chooses to make its <code>initial_suspend<\/code> method return a suspending awaiter. <code>IAsyncAction<\/code> and <code>IAsyncOperation<\/code> are eager-start, so the C++\/WinRT libray&#8217;s <code>initial_suspend<\/code> is <code>suspend_never<\/code>, thereby allowing the coroutine to begin executing its body. By adding an immediate suspension point as the first thing in the body, we are sort of retroactively changing that <code>suspend_never<\/code> into a suspension. If you look at <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210331-00\/?p=105028\"> one of the rewrite steps in the coroutine transformation<\/a>, you&#8217;ll see that the coroutine function body comes immediately after the <code>initial_suspend<\/code>, so our immediate suspension is functionally equivalent to rewriting the <code>initial_suspend<\/code>.<\/p>\n<p>We will expand upon this idea next time, when we work on serializing asynchronous operations in C++\/WinRT.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Keeping a turkey in suspense.<\/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-107175","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Keeping a turkey in suspense.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107175","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=107175"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107175\/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=107175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}