{"id":105009,"date":"2021-03-26T07:00:00","date_gmt":"2021-03-26T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105009"},"modified":"2021-03-26T08:03:08","modified_gmt":"2021-03-26T15:03:08","slug":"20210326-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210326-00\/?p=105009","title":{"rendered":"Creating a task completion source for a C++ coroutine: Failing to produce a result"},"content":{"rendered":"<p>So far, we&#8217;ve been working on <a title=\"Creating a task completion source for a C++ coroutine: Producing nothing\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210325-00\/?p=105002\"> building a <code>result_holder<\/code> that can hold any type of result. But what about errors? <\/a><\/p>\n<p>Because maybe you have code that&#8217;s waiting for a result, and the code that&#8217;s supposed to produce the result realizes that it messed up and wants to say, &#8220;Sorry, no result today.&#8221;<\/p>\n<p>We can do that by storing a <code>std::<wbr \/>exception_<wbr \/>ptr<\/code> as a possible result. This means that our result is no longer merely an optional value, but rather it&#8217;s a variant, since it could be empty, or it could have a value, or it could have an exception. It also means that <code>ready<\/code> needs to become a discriminant.<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct result_holder_state :\r\n    async_helpers::awaitable_state&lt;result_holder_state&lt;T&gt;&gt;\r\n{\r\n    <span style=\"color: blue;\">enum class result_kind {\r\n        unset,\r\n        value,\r\n        exception,\r\n    };\r\n\r\n    std::atomic&lt;result_kind&gt; kind{ result_kind::unset };<\/span>\r\n\r\n    struct wrapper\r\n    {\r\n        T value;\r\n    };\r\n\r\n    <span style=\"color: blue;\">union variant\r\n    {\r\n        variant() {}\r\n        ~variant() {}\r\n\r\n        wrapper wrap;\r\n        std::exception_ptr ex;\r\n    } result;<\/span>\r\n\r\n    result_holder_state() {}\r\n    result_holder_state(result_holder_state const&amp;) = delete;\r\n    void operator=(result_holder_state const&amp;) = delete;\r\n\r\n    ~result_holder_state()\r\n    {\r\n        <span style=\"color: blue;\">switch (kind.load(std::memory_order_relaxed)) {\r\n        case result_kind::value:\r\n            result.wrap.~wrapper();\r\n            break;\r\n        case result_kind::exception:\r\n            result.ex.~exception_ptr();\r\n            break;\r\n        }<\/span>\r\n    }\r\n\r\n    using typename result_holder_state::extra_await_data;\r\n    using typename result_holder_state::node_list;\r\n\r\n    bool fast_claim(extra_await_data const&amp;) noexcept\r\n    {\r\n        return kind.load(std::memory_order_acquire)\r\n            <span style=\"color: blue;\">!= result_kind::unset<\/span>;\r\n    }\r\n\r\n    bool claim(extra_await_data const&amp;) noexcept\r\n    {\r\n        return kind.load(std::memory_order_relaxed)\r\n            <span style=\"color: blue;\">!= result_kind::unset<\/span>;\r\n    }\r\n\r\n    void set_result(node_list&amp; list, T v)\r\n    {\r\n        if (<span style=\"color: blue;\">kind.load(std::memory_order_relaxed)\r\n            == result_kind::unset<\/span>) {\r\n            new (std::addressof(result.wrap))\r\n                wrapper{ std::forward&lt;T&gt;(v) };\r\n            <span style=\"color: blue;\">kind.store(result_kind::value<\/span>,\r\n                std::memory_order_release);\r\n            this-&gt;resume_all(list);\r\n        }\r\n    }\r\n\r\n    <span style=\"color: blue;\">void set_exception(\r\n        node_list&amp; list, std::exception_ptr ex)\r\n    {\r\n        if (kind.load(std::memory_order_relaxed)\r\n            == result_kind::unset) {\r\n            new (std::addressof(result.ex))\r\n                std::exception_ptr{ std::move(ex) };\r\n            kind.store(result_kind::exception,\r\n                std::memory_order_release);\r\n            this-&gt;resume_all(list);\r\n        }\r\n    }<\/span>\r\n\r\n    T get_result()\r\n    {\r\n        <span style=\"color: blue;\">switch (kind.load(std::memory_order_relaxed)) {\r\n        case result_kind::value:\r\n            return result.wrap.value;\r\n        case result_kind::exception:\r\n            std::rethrow_exception(result.ex);\r\n        }\r\n        std::terminate(); \/\/ shouldn't get here<\/span>\r\n    }\r\n};\r\n<\/pre>\n<p>There isn&#8217;t much exciting going on here. It&#8217;s just changing the things that need to be changed: Instead of a simple <code>bool<\/code> tracking what is in the <code>result<\/code>, we use a discriminant which starts out <code>unset<\/code>. Cleaning up our variant requires us to call the appropriate destructor for the contents of the <code>result<\/code>, and setting the result requires us to update the discriminant.<\/p>\n<p>Setting an exception is the same as setting a value, except that we put the result in to the <code>ex<\/code> member instead of the <code>wrap<\/code> wrapper.<\/p>\n<p>When it comes time to fetch the result, we check what we have. If we have a value, we return it. If we have an exception, we rethrow it. (Otherwise, something went wrong and we terminate.)<\/p>\n<p>The <code>result_<wbr \/>holder<\/code> itself is basically the same, just with an extra method for storing the exception.<\/p>\n<pre>template&lt;typename T&gt;\r\nstruct result_holder\r\n    : async_helpers::awaitable_sync_object&lt;\r\n        result_holder_state&lt;T&gt;&gt;\r\n{\r\n    using typename result_holder::state;\r\n\r\n    void set_result(T result) const noexcept\r\n    {\r\n        this-&gt;action_impl(&amp;state::set_result,\r\n            std::move(result));\r\n    }\r\n\r\n    <span style=\"color: blue;\">void set_exception(std::exception_ptr ex) const noexcept\r\n    {\r\n        this-&gt;action_impl(&amp;state::set_exception,\r\n            std::move(ex));\r\n    }<\/span>\r\n};\r\n<\/pre>\n<p>The Windows Runtime <code>IAsync\u00adOperation<\/code> can be awaited only once, but you can use this <code>result_<wbr \/>holder<\/code> to make it possible to await multiple times.<\/p>\n<pre>template&lt;typename T&gt;\r\nresult_holder&lt;T&gt; MakeMultiAwaitable(IAsyncOperation&lt;T&gt; async)\r\n{\r\n    result_holder&lt;T&gt; holder;\r\n    async.Completed([holder, async](auto, auto status) {\r\n        try {\r\n            switch (status) {\r\n            case AsyncStatus::Completed:\r\n                holder.set_result(async.GetResults());\r\n                break;\r\n            case AsyncStatus::Canceled:\r\n                throw hresult_canceled();\r\n            case AsyncStatus::Error:\r\n                throw_hresult(async.ErrorCode());\r\n            }\r\n        } catch (...) {\r\n            holder.set_exception(std::current_exception());\r\n        }\r\n    });\r\n    return holder;\r\n}\r\n<\/pre>\n<p>You would use it something like this:<\/p>\n<pre>class MyClass\r\n{\r\n    result_holder&lt;Widget&gt; widget_result;\r\n\r\n    MyClass()\r\n    {\r\n        \/\/ Kick off initialization but don't wait for it.\r\n        widget_result = MakeMultiAwaitable(InitializeAsync());\r\n    }\r\n\r\n    IAsyncOperation&lt;Widget&gt; InitializeAsync();\r\n\r\n    IAsyncAction DoSomethingAsync()\r\n    {\r\n        \/\/ Wait for the widget that InitializeAsync produced.\r\n        \/\/ rethrow any exception that occurred during initialization.\r\n        auto widget = co_await widget_result;\r\n        ... do something interesting ...\r\n    }\r\n};\r\n<\/pre>\n<p>More generally, you would do something like this:<\/p>\n<pre>void CalculateResult(result_holder&lt;Widget&gt;&amp; holder)\r\n{\r\n    try\r\n    {\r\n        \/* do a bunch of calculations *\/\r\n        widget = \/* the answer *\/;\r\n        holder.set_result(widget);\r\n    } catch (...) {\r\n        holder.set_exception(std::current_exception());\r\n    }\r\n}\r\n<\/pre>\n<p>You know what this looks like?<\/p>\n<p>A coroutine!<\/p>\n<pre>result_holder&lt;Widget&gt; CalculateResult()\r\n{\r\n    \/* do a bunch of calculations *\/\r\n    widget = \/* the answer *\/;\r\n    co_return widget;\r\n\r\n    \/* exception is captured into the result_holder *\/\r\n}\r\n<\/pre>\n<p>So I guess it&#8217;s time to learn how to create our own coroutines. The dive into the deep end begins next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Stowing an exception.<\/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-105009","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Stowing an exception.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105009","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=105009"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105009\/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=105009"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105009"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105009"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}