{"id":105093,"date":"2021-04-13T07:00:00","date_gmt":"2021-04-13T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105093"},"modified":"2021-04-13T07:55:20","modified_gmt":"2021-04-13T14:55:20","slug":"20210413-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210413-00\/?p=105093","title":{"rendered":"C++ coroutines: Tradeoffs of making the promise be the shared state"},"content":{"rendered":"<p>Last time, we <a title=\"C++ coroutines: The lifetime of objects involved in the coroutine function\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210412-00\/?p=105078\"> traced the lifetimes of the objects involved in the coroutine function<\/a>. Now we can look at some of the tradeoffs we&#8217;ve made in our design and see how the decisions are intertwined.<\/p>\n<p>Inlining the shared state into the promise itself has the advantage of avoiding an extra allocation, which is significant when coroutines are being created frequently. However, it also means that as long as there is an active task that refers to the coroutine, the entire coroutine state will remain allocated, even though most of it is not being used.<\/p>\n<p>We therefore want to discourage clients from holding onto the task after the <code>co_await<\/code>. If the object could be <code>co_await<\/code>ed multiple times, then the task will need to be shared, and it will probably have a long life. For example, an initialization task would probably be stored with a long lifetime, so that every method on the object could <code>co_await<\/code> the initialization task to ensure that initialization was complete before proceeding.<\/p>\n<p>Making the object <code>co_await<\/code>able only once would discourage clients from retaining the task after the <code>co_await<\/code>, since the object is useless after that point. Making the object <code>co_await<\/code>able only once also allows the result to be a move-only type, since there is only one consumer, and we can just move the result to that consumer. If the object could be <code>co_await<\/code>ed more than once, then each consumer would have to receive a copy.<\/p>\n<p>Conversely, if we want the object to be <code>co_await<\/code>able multiple times, then we should keep the return value in a separate object and jettison the coroutine state as soon as possible in order to destruct the coroutine parameters as well as reclaim the memory formerly occupied by local variables and temporaries.<\/p>\n<p>I find it interesting that these decisions are intertwined. Separate return object = multiply-awaitable = long lifetime. Embedded return object = singly-awaitable = short lifetime.<\/p>\n<p>After writing up this discussion, it occurred to me that my simple promise implementation (which follows the embedded return object, singly-awaitable, short lifetime model) was working too hard. I&#8217;ll simplify it next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Are you meant to be ephemeral, or are you intended to be durable?<\/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-105093","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Are you meant to be ephemeral, or are you intended to be durable?<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105093","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=105093"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105093\/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=105093"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105093"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105093"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}