{"id":103195,"date":"2019-12-09T07:00:00","date_gmt":"2019-12-09T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103195"},"modified":"2019-12-08T16:39:51","modified_gmt":"2019-12-09T00:39:51","slug":"20191209-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191209-00\/?p=103195","title":{"rendered":"C++ coroutines: Getting started with awaitable objects"},"content":{"rendered":"<p>Coroutines were added to C++20, and <a href=\"http:\/\/lewissbaker.github.io\/\"> Lewis Baker<\/a> has a nice introduction to them.<\/p>\n<ul>\n<li><a href=\"https:\/\/lewissbaker.github.io\/2017\/09\/25\/coroutine-theory\"> Coroutine theory<\/a>.<\/li>\n<li><a href=\"https:\/\/lewissbaker.github.io\/2017\/11\/17\/understanding-operator-co-await\"> Understanding <code>operator co_await<\/code><\/a>.<\/li>\n<li><a href=\"https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type\n\"> Understanding the promise type<\/a>.<\/li>\n<\/ul>\n<p>But I&#8217;m going to write another one, taking a more practical approach: The least you need to know to accomplish various coroutine tasks.<\/p>\n<p>We&#8217;ll start by looking at awaitable objects: Things that can be passed to <code>co_await<\/code>.<\/p>\n<p>When you do a <code>co_await x<\/code>, the compiler tries to come up with a thing called an <i>awaiter<\/i>.<\/p>\n<ol>\n<li>(We&#8217;re not ready to talk about step 1 yet.)<\/li>\n<li>(We&#8217;re not ready to talk about step 2 yet.)<\/li>\n<li>Otherwise, <code>x<\/code> is its own awaiter.<\/li>\n<\/ol>\n<p>Now that we have an awaiter, we can use it to wait for <code>x<\/code> to complete. I&#8217;ll start with the basic idea, and then gradually make it more complicated.<\/p>\n<p>The basic idea is that the compiler generates code like this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>\n<div>calculate <code>x<\/code><\/div>\n<div>obtain <code>awaiter<\/code><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"2\" valign=\"middle\"><code>co_await<\/code><\/td>\n<td style=\"border: solid 1px black;\">\n<div>(We&#8217;re not ready to talk about this step yet.)<\/div>\n<div>save state for resumption<\/div>\n<div><code>awaiter.await_suspend(handle);<\/code><\/div>\n<div>(We&#8217;re not ready to talk about this step yet.)<\/div>\n<div>return to caller<\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\">\n<div>[Invoking the handle resumes execution here]<\/div>\n<div>restore state after resumption<\/div>\n<div><code>result = awaiter.await_resume();<\/code><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>execution continues<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The main job of the <code>await_suspend<\/code> method is to arrange <i>somehow<\/i> for the <code>handle<\/code> to be invoked when it&#8217;s time for the <code>co_await<\/code> to be considered to have completed execution.<\/p>\n<p>The main job of the <code>await_resume<\/code> method is to report the result of the <code>co_await<\/code> operation. If the <code>await_resume<\/code> method returns <code>void<\/code>, then the <code>co_await<\/code> also returns <code>void<\/code>.<\/p>\n<p>You can invoke the <code>handle<\/code> at any time once the <code>await_suspend<\/code> starts. It&#8217;s even possible (for example, due to race conditions) that the <i>somehow<\/i> caused the <code>handle<\/code> to be invoked even before the <code>await_suspend<\/code> finishes running. The entire function could even have run to completion!<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>Thread 1<\/td>\n<td>Thread 2<\/td>\n<\/tr>\n<tr>\n<td style=\"border-right: solid 1px black;\">\n<div>calculate <code>x<\/code><\/div>\n<div>obtain <code>awaiter<\/code><\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-right: solid 1px black;\">\n<div>save state for resumption<\/div>\n<div><code>awaiter.await_suspend<\/code><\/div>\n<div><code>{<\/code><\/div>\n<div style=\"padding-left: 2em;\">schedule <code>handler<\/code> to execute<\/div>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-right: solid 1px black;\">\u00a0<\/td>\n<td>\n<div><code>handler<\/code> is invoked<\/div>\n<div>restore state after resumption<\/div>\n<div><code>result = awaiter.await_resume();<\/code><\/div>\n<div>execution continues<\/div>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"border-right: solid 1px black;\">\n<div style=\"padding-left: 2em;\">does final work<\/div>\n<div><code>}<\/code><\/div>\n<div>return to caller<\/div>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>One of the things that will happen when execution continues is that the awaiter destructs according to the normal rules. In particular, if the awaiter was a temporary (and it almost always is), then it destructs according to the rules for destruction of temporaries.<\/p>\n<p>Observe that the <code>handler<\/code> was invoked before <code>await_<\/code><code>suspend<\/code> could finish running. Any attempt to use members of the temporary <code>awaiter<\/code> will use an object after it has been destructed.<\/p>\n<p>Therefore, it is important that your awaiter not use its <code>this<\/code> pointer once it has arranged for the <code>handle<\/code> to be invoked <i>somehow<\/i>, because the <code>this<\/code> pointer may no longer be valid.<\/p>\n<p>The C++ language coroutine library comes with a predefined awaiter known as <code>suspend_<\/code><code>always<\/code>. Its <code>await_suspend<\/code> throws away the handle without doing anything, which means that the continuation will never run. In other words, <code>suspend_<\/code><code>always<\/code> suspends and never wakes up. Like a dark version of the Snow White fairy tale.<\/p>\n<p>Now, you may think that <code>suspend_<\/code><code>always<\/code> is not particularly useful, seeing as it basically hangs the coroutine. But it&#8217;s a convenient starting point to build on, because it fills out all the necessary paperwork for being an awaiter. All you have to do is provide a better <code>await_<\/code><code>suspend<\/code> method.<\/p>\n<p>Even with this extremely rudimentary understanding of coroutines, we can already write something interesting.<\/p>\n<pre>struct resume_new_thread : std::experimental::suspend_always\r\n{\r\n  void await_suspend(\r\n      std::experimental::coroutine_handle&lt;&gt; handle)\r\n  {\r\n    std::thread([handle]{ handle(); }).detach();\r\n  }\r\n};\r\n<\/pre>\n<p>Since is this our first time, let&#8217;s walk through the steps one at a time.<\/p>\n<p>When you do a<\/p>\n<pre>co_await resume_new_thread();\r\n<\/pre>\n<p>we start by default-constructing a <code>resume_<\/code><code>new_<\/code><code>thread<\/code> object.<\/p>\n<p>The compiler then sees that you are <code>co_await<\/code>ing it, so it saves the coroutine state, and then step 3 above treats the object as its own awaiter, so the compiler calls the <code>await<\/code><code>_suspend<\/code> method.<\/p>\n<p>Our custom awaiter suspends the coroutine by creating a thread, detaching it (so it continues to run after the thread object destructs), and returns.<\/p>\n<p>The thread runs the lambda. The lambda invokes the coroutine handle, which resumes the coroutine.\u00b9<\/p>\n<p>Upon resumption, the compiler calls the <code>await_<\/code><code>resume<\/code> method to get the result. The built-in <code>suspend_<\/code><code>always<\/code> has an <code>await_<\/code><code>resume<\/code> method that returns nothing, and since we didn&#8217;t override it, our custom awaiter also returns nothing. In other words, the result of the <code>co_await<\/code> is <code>void<\/code>.<\/p>\n<p>And finally, we have reached the end of the full expression, so the temporary <code>resume_<\/code><code>new_<\/code><code>thread<\/code> object destructs.<\/p>\n<p>The result of this exercise is that if you do a<\/p>\n<pre>co_await resume_new_thread();\r\n<\/pre>\n<p>your coroutine resumes in a new thread. It&#8217;s magic!\u00b2<\/p>\n<pre>winrt::fire_and_forget StartWidget(\r\n    std::shared_ptr&lt;Widget&gt; widget,\r\n    WidgetStartOptions options)\r\n{\r\n    auto ticket = widget-&gt;GetStartTicket(options);\r\n    co_await resume_new_thread();\r\n    widget-&gt;PlugIn();\r\n    widget-&gt;SwitchOn();\r\n    \/\/ ticket destructor runs here\r\n}\r\n<\/pre>\n<p>In this example, we have a coroutine that does some up-front validation by trying to obtain a start ticket. And then it moves to a new thread for actually performing the widget operations to get the thing started. At the close-brace, the ticket destructs, which releases the widget to be manipulated by others. Also at the close-brace, the function parameters are destructed. In this case, it means that the <code>shared_<\/code><code>ptr<\/code> and <code>options<\/code> destruct.<\/p>\n<p>Note that the destruction of the <code>ticket<\/code>, <code>shared_ptr<\/code>, and <code>options<\/code> all occur on the new thread, not on the original thread.<\/p>\n<p>These simple one-shot awaitables are typically either simple objects or functions that return simple objects. In this case, it was a simple object. Next time, we&#8217;ll look at the function pattern and compare the two patterns.<\/p>\n<p><b>Bonus chatter<\/b>: C++ coroutines are single-use. Once you invoke the handle, it is dead and may not be invoked again.<\/p>\n<p>\u00b9 The <code>std::thread<\/code> constructor accepts any <i>Callable<\/i>, and the <code>coroutine_<\/code><code>handle&lt;&gt;<\/code> is itself callable. Therefore, we could have written the function a bit more tersely as<\/p>\n<pre>  void await_suspend(\r\n      std::experimental::coroutine_handle&lt;&gt; handle)\r\n  {\r\n    std::thread(<span style=\"color: blue;\">handle<\/span>).detach();\r\n  }\r\n<\/pre>\n<p>\u00b2 Observe that in the <code>resume_<\/code><code>new_<\/code><code>thread<\/code> example, it&#8217;s possible for the new thread to start up and run to completion before our <code>await_<\/code><code>suspend<\/code> finishes. This is an example of the race condition I cautioned about earlier.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Starting our walk-around.<\/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-103195","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Starting our walk-around.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103195","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=103195"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103195\/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=103195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}