{"id":100715,"date":"2019-01-16T07:00:00","date_gmt":"2019-01-16T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=100715"},"modified":"2019-03-13T00:07:37","modified_gmt":"2019-03-13T07:07:37","slug":"20190116-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190116-00\/?p=100715","title":{"rendered":"How do I get the effect of C#&#8217;s <CODE>async void<\/CODE> in a C++ coroutine? Part 1: Why does the obvious solution crash?"},"content":{"rendered":"<p>The <code>co_await<\/code> C++ language keyword makes it a lot easier to write coroutines. The compiler does the grunt work of transforming your function into a state machine, similar in spirit to the coroutine transformations performed by <a HREF=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/concepts\/async\/\">C#<\/a> and <a HREF=\"https:\/\/www.wptutor.io\/web\/js\/generators-coroutines-async-javascript\/\">JavaScript<\/a>. <\/p>\n<p>C# and JavaScript have an additional feature that C++ doesn&#8217;t: They let you take a coroutine and treat it like a plain function which returns when the coroutine yields for the first time. With C#, this is done by declaring the function as <code>async void<\/code>. With JavaScript, you get this automatically because JavaScript is dynamically-typed. <\/p>\n<p>But you don&#8217;t get any built-in help in C++. <\/p>\n<pre>\ntypedef void (*EventHandler_t)(int a, int b);\n\nvoid MyEventHandler(int a, int b)\n{\n  GetReady(a);\n  <font COLOR=\"blue\">co_await GetSetAsync(b); \/\/ oops - this doesn't compile<\/font>\n  Go(a, b);\n}\n\nextern void SetEventHandler(EventHandler_t eventHandler);\n\nvoid RegisterTheEventHandler()\n{\n   SetEventHandler(MyEventHandler);\n}\n<\/pre>\n<p>In order to use <code>co_await<\/code>, your function must return a <code>future<\/code> or <code>task<\/code> or some other representation of a coroutine. <\/p>\n<p>Okay, so let&#8217;s do that. <\/p>\n<pre>\ntypedef void (*EventHandler_t)(int a, int b);\n\nConcurrency::task&lt;void&gt; MyEventHandler(int a, int b)\n{\n  GetReady(a);\n  co_await GetSetAsync(b); \/\/ all right, now this compiles!\n  Go(a, b);\n}\n\nextern void SetEventHandler(EventHandler_t eventHandler);\n\nvoid RegisterTheEventHandler()\n{\n   <font COLOR=\"blue\">SetEventHandler(MyEventHandler); \/\/ but this doesn't<\/font>\n}\n<\/pre>\n<p>So now what? <\/p>\n<p>If you&#8217;re lucky, your event handler takes a <code>std::function<\/code>, which is more generous about function return types, and the problem goes away. <\/p>\n<p>But suppose you&#8217;re not that lucky. <\/p>\n<p>Gor Nishanov, one of the brains behind <code>co_await<\/code>, <a HREF=\"https:\/\/channel9.msdn.com\/Events\/Build\/2016\/P489#c635962709818402409\">had two suggestions<\/a>. The first is to create a wrapper. <\/p>\n<pre>\nConcurrency::task&lt;void&gt; MyEventHandlerAsync(int a, int b)\n{\n  GetReady(a);\n  co_await GetSetAsync(b);\n  Go(a, b);\n}\n\n<font COLOR=\"blue\">void MyEventHandler(int a, int b)\n{\n  MyEventHandlerAsync(); \/\/ throw away the task\n}<\/font>\n\nextern void SetEventHandler(EventHandler_t eventHandler);\n\nvoid RegisterTheEventHandler()\n{\n   SetEventHandler(MyEventHandler);\n}\n<\/pre>\n<p>The other is to roll up your sleeves and write a specialization of <code>coroutine_<\/code><code>traits<\/code> to support returning <code>void<\/code>. I&#8217;m not going to reproduce it here because it assumes you understand the low-level machinery that makes <code>co_await<\/code> work,&sup1; and it ties you to a specific asynchronous framework (since it&#8217;s going to be used for all functions returning <code>void<\/code>). <\/p>\n<p>I thought I discovered a third way: <\/p>\n<pre>\n\/\/ Code in italics is wrong.\nvoid MyEventHandler(int a, int b)\n{\n  <font COLOR=\"blue\"><i>[=]() -&gt; Concurrency::task&lt;void&gt;<\/i>\n  {<\/font>\n    GetReady(a);\n    co_await GetSetAsync(b);\n    Go(a, b);\n  <font COLOR=\"blue\">}();<\/font>\n}\n\nextern void SetEventHandler(EventHandler_t eventHandler);\n\nvoid RegisterTheEventHandler()\n{\n   SetEventHandler(MyEventHandler);\n}\n<\/pre>\n<p>We create a lambda that returns a coroutine, and that lambda can now use <code>co_await<\/code>. And then we invoke the lambda immediately and throw the result away. <\/p>\n<p>This does cost you a level of indentation, but it beats writing another function entirely. <\/p>\n<p>Basically, I just took Gor&#8217;s first suggestion and inlined the function as a lambda. <\/p>\n<p>Unfortunately, it also doesn&#8217;t work. <\/p>\n<p>To see why, let&#8217;s write out the lambda in its expanded form. <\/p>\n<pre>\nvoid MyEventHandler(int a, int b)\n{\n  <i>struct Lambda {\n   Lambda(int a, int b) : a_(a), b_(b) { }\n   Concurrency::task&lt;void&gt; operator() {\n    GetReady(a_);\n    co_await GetSetAsync(b_);\n    Go(a_, b_);\n   }\n  private:\n   int a_, b_;\n  } lambda(a, b);\n\n  lambda();<\/i>\n}\n<\/pre>\n<p>To make things even more explicit, let&#8217;s expand out the task, too. <\/p>\n<pre>\nvoid MyEventHandler(int a, int b)\n{\n  <i>struct LambdaFrame {\n   LambdaFrame(Lambda* lambda) : lambda_(lambda) { }\n\n   Concurrency::task&lt;void&gt; Run() {\n    if (state_ == 0) {\n     GetReady(lambda_-&gt;a_);\n     auto innerTask = GetSetAsync(lambda_-&gt;b_);\n     state_ = 1;\n     return magic_create_task_from_frame(this);\n    } else if (state_ == 1) {\n     Go(lambda_-&gt;a_, lambda_-&gt;b_);\n     state_ = 2;\n     return magic_completed_task();\n    }\n   }\n  private:\n   Lambda* lambda_;\n   int state_ = 0;\n  };\n\n  struct Lambda {\n   Lambda(int a, int b) : a_(a), b_(b) { }\n   Concurrency::task&lt;void&gt; operator() {\n    return magic_create_task_from_frame\n            &lt;LambdaFrame&gt;(__this, a_, b_);\n   }\n  private:\n   int a_, b_;\n  } lambda(a, b);\n\n  lambda();<\/i>\n}\n<\/pre>\n<p>I&#8217;m glossing over a bunch of <code>magic_<\/code> stuff which is part of the behind-the-scenes coroutine infrastructure. The important thing is that the <code>task<\/code> keeps the <code>Lambda&shy;Frame<\/code> alive for as long as the task needs it. <\/p>\n<p>But there is no magic that keeps the <code>lambda<\/code> alive! <\/p>\n<p>What we did was invoke the lambda and then destruct it when the function returns. But the task is still running, and that task is going to try to use the <code>a_<\/code> and <code>b_<\/code> members of the lambda. Which no longer exists. <\/p>\n<p>In other words, we have a case of using an object after it has destructed. <\/p>\n<p>But wait, all is not lost. We can fix this by using a non-capturing lambda. <\/p>\n<pre>\nvoid MyEventHandler(int a, int b)\n{\n  [](int a, int b) -&gt; Concurrency::task&lt;void&gt;\n  {\n   GetReady(a);\n   co_await GetSetAsync(b);\n   Go(a, b);\n  }(a, b);\n}\n<\/pre>\n<p>We cannot capture state in the lambda because the lambda is going to be destructed as soon as the task reaches a suspension point. Instead, we capture the state in the explicit lambda parameters (which are part of the frame, not the lambda). <\/p>\n<p>If <code>My&shy;Event&shy;Handler<\/code> is a member function, you&#8217;ll also have to capture <code>this<\/code> explicitly. Furthermore, you need to make sure the instance doesn&#8217;t get destructed while the task is running. This might be implicit in the way you use the task, or it could be explicit by maintaining a strong reference to the enclosing object. <\/p>\n<pre>\nvoid MyClass::MyEventHandler(int a, int b)\n{\n  [](std::shared_ptr&lt;MyClass&gt; self, int a, int b)\n   -&gt; Concurrency::task&lt;void&gt;\n  {\n   self-&gt;GetReady(a);\n   co_await self-&gt;GetSetAsync(b);\n   self-&gt;Go(a, b);\n  }(this-&gt;shared_from_this(), a, b);\n}\n<\/pre>\n<p>Unfortunately, having to type <code>self-&gt;<\/code> each time you access a member makes this rather cumbersome. To solve this, you can make the lambda body a separate method. But now you&#8217;ve come full circle back to Gor&#8217;s original suggestion. <\/p>\n<p>So is this hopeless? Not quite. We&#8217;ll pick up the story next time. <\/p>\n<p>&sup1; If you want to learn the low-level machinery that makes <code>co_await<\/code> work, you can read this series of articles by <a HREF=\"https:\/\/lewissbaker.github.io\/\">Lewis Baker<\/a>: <\/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 operator co_await<\/a><\/li>\n<li>    <a HREF=\"https:\/\/lewissbaker.github.io\/2018\/09\/05\/understanding-the-promise-type\">    Understanding the promise type<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Wrap it up, but watch out how you do it.<\/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-100715","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Wrap it up, but watch out how you do it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100715","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=100715"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100715\/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=100715"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=100715"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=100715"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}