{"id":103201,"date":"2019-12-11T07:00:00","date_gmt":"2019-12-11T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103201"},"modified":"2019-12-10T21:25:44","modified_gmt":"2019-12-11T05:25:44","slug":"20191211-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191211-00\/?p=103201","title":{"rendered":"C++ coroutines: Framework interop"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191210-00\/?p=103197\"> So far<\/a>, we&#8217;ve been looking at the basics of awaitable objects. Even though we barely know anything beyond <code>await_<\/code><code>suspend<\/code>, we already know enough to allow us to start diving deeper.<\/p>\n<p>It is frequently the case that you need your awaiter to interact with something outside the C++ standard library. To make it easier to integrate coroutines with existing frameworks, the <code>coroutine_handle<\/code> can be converted to a <code>void*<\/code> by calling its <code>address()<\/code> method, and the resulting <code>void*<\/code> can be converted back to an equivalent <code>coroutine_handle<\/code> by calling <code>from_<\/code><code>address()<\/code>.\u00b9<\/p>\n<p>Most frameworks let you pass a pointer-sized piece of data around to help remember state, and being able to convert a handle into a pointer (and back) lets you pass the coroutine handle through such state parameters. Otherwise, you&#8217;d have to copy the <code>coroutine_handle<\/code> to the heap and pass the address of the heap block, and then keep track of when to free the heap block.<\/p>\n<p>Let&#8217;s demonstrate this by reimplementing <code>resume_<\/code><code>new_<\/code><code>thread<\/code> in terms of Win32 functions instead of the <code>std::<\/code><code>thread<\/code> standard library class.<\/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    HANDLE thread = CreateThread(nullptr, 0, callback,\r\n                        handle.address(), 0, &amp;threadId);\r\n    if (!thread) throw some_kind_of_error();\r\n    CloseHandle(thread);\r\n  }\r\n\r\n  DWORD CALLBACK callback(void* parameter)\r\n  {\r\n    auto handle = std::experimental::coroutine_handle&lt;&gt;::\r\n                    from_address(parameter);\r\n    handle();\r\n    return 0;\r\n  }\r\n};\r\n<\/pre>\n<p>The basic idea is the same as last time: When the coroutine suspends, schedule the continuation on a newly-created thread.<\/p>\n<p>The <code>Create\u00adThread<\/code> function allows you to pass a single pointer-sized piece of data, so we convert our handle to a <code>void*<\/code> by calling the <code>address<\/code> method, and pass that pointer as the reference data to the thread procedure. The thread procedure converts the pointer back into a coroutine handle by calling <code>from_<\/code><code>address<\/code>, and then invokes the coroutine to resume execution.<\/p>\n<p>If terseness is your game, you could inline the thread procedure as a stateless lambda, taking advantage of <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150220-00\/?p=44623\"> the implicit conversion from a stateless lambda to a function pointer<\/a>.<\/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    HANDLE thread = CreateThread(nullptr, 0,\r\n      [](void* parameter) -&gt; DWORD\r\n      {\r\n        std::experimental::coroutine_handle&lt;&gt;::\r\n                    from_address(parameter)();\r\n        return 0;\r\n      }, handle.address(), 0, &amp;threadId);\r\n    if (!thread) throw some_kind_of_error();\r\n    CloseHandle(thread);\r\n  }\r\n};\r\n<\/pre>\n<p>Next time, we&#8217;ll use what we&#8217;ve learned about awaiters to develop a way to override C++\/WinRT coroutine threading defaults.<\/p>\n<p>\u00b9 The method names <code>address<\/code> and <code>from_<\/code><code>address<\/code> give a strong clue as to what the <code>void*<\/code> represents: it&#8217;s the address of runtime-managed coroutine state, known in the language specification as a <i>coroutine frame<\/i>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Plays well with others.<\/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-103201","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Plays well with others.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103201","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=103201"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103201\/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=103201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}