{"id":5455,"date":"2018-06-15T19:58:40","date_gmt":"2018-06-15T19:58:40","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/the-end-of-the-detour-unified-futures\/"},"modified":"2023-06-26T11:49:28","modified_gmt":"2023-06-26T11:49:28","slug":"the-end-of-the-detour-unified-futures","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/the-end-of-the-detour-unified-futures\/","title":{"rendered":"The End of my Detour: Unified Futures"},"content":{"rendered":"<p>After the last post to <a href=\"https:\/\/www.modernescpp.com\/index.php\/a-short-detour-executors\">executors,<\/a> I can finally write about the unified futures. I write in the post about the long past of the futures and end my detour from the C++ core guidelines.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5454\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/technology-2025795_1280.jpg\" alt=\"technology 2025795 1280\" width=\"500\" height=\"332\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/technology-2025795_1280.jpg 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/technology-2025795_1280-300x199.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/technology-2025795_1280-1024x681.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/06\/technology-2025795_1280-768x511.jpg 768w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<p>The long past of promises and futures began in C++11.<\/p>\n<h2>C++11: The standardized futures<\/h2>\n<p>Tasks in the form of promises and futures have an ambivalent reputation in C++11. Conversely, they are much easier to use than threads or condition variables; conversely, they have a significant deficiency. They cannot be composed. C++20\/23 may overcome this deficiency. I have written about tasks in the form of <span style=\"font-family: courier new, courier;\">std::async<\/span>, <span style=\"font-family: courier new, courier;\">std::packaged_task,<\/span> or <span style=\"font-family: courier new, courier;\">std::promise<\/span> and <span style=\"font-family: courier new, courier;\">std::future<\/span>. For the details: read my posts on <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/tasks\">tasks<\/a>. With C++20\/23, we may get extended futures.<\/p>\n<\/p>\n<h2>Concurrency TS: The extended futures<\/h2>\n<p>Because of the issues of futures, the <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/experimental\/concurrency\">ISO\/IEC TS 19571:2016<\/a> added extensions to the futures. From the bird&#8217;s eye perspective, they support composition. An extended future becomes ready when its predecessor <span style=\"font-family: courier new, courier;\">(then)<\/span> becomes ready, <span style=\"font-family: courier new, courier;\">when_any<\/span> one of its predecessors becomes ready, or <span style=\"font-family: courier new, courier;\">when_all <\/span>of its predecessors becomes ready. They are available in the namespace <span style=\"font-family: courier new, courier;\">std::experimental. <\/span>In case you are curious, here are the details: <a href=\"https:\/\/www.modernescpp.com\/index.php\/std-future-extensions\"><span style=\"font-family: courier new, courier;\">std::future Extensions<\/span><\/a>.<\/p>\n<p>This was not the endpoint of a lengthy discussion. With the renaissance of the executors, the future of the futures changed.<\/p>\n<h2>Unified Futures<\/h2>\n<p>The paper <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2017\/p0701r1.html\">P0701r1: Back to the std2::future Part II <\/a>gives an excellent overview of the disadvantages of the existing and the extended futures.<\/p>\n<h3>Disadvantages of the Existing Futures<\/h3>\n<h4><span style=\"font-family: courier new, courier;\">future\/promise<\/span> Should Not Be Coupled to <span style=\"font-family: courier new, courier;\">std::thread<\/span> Execution Agents<\/h4>\n<p>C++11 had only one executor: <span style=\"font-family: courier new, courier;\">std::thread<\/span>. Consequently, futures and <span style=\"font-family: courier new, courier;\">std::thread<\/span> were inseparable. This changed with C++17 and the parallel algorithms of the STL. This changes even more with the new executors you can use to configure the future. For example, the future may run in a separate thread, in a thread pool, or just sequentially.<\/p>\n<h4>Where are <span style=\"font-family: courier new, courier;\">.then<\/span> Continuations are Invoked?<\/h4>\n<p>Imagine you have a simple continuation, such as in the following example.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">future f1 <span style=\"color: #555555;\">=<\/span> async([]{ <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">123<\/span>; });\r\nfuture f2 <span style=\"color: #555555;\">=<\/span> f1.then([](future f) {\r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> to_string(f.get());\r\n});\r\n<\/pre>\n<\/div>\n<p>The question is: Where should the continuation run? There are a few possibilities today:<\/p>\n<ol>\n<li><strong>Consumer Side<\/strong>: The consumer execution agent always executes the continuation.<\/li>\n<li><strong>Producer Side<\/strong>: The producer execution agent always executes the continuation.<\/li>\n<li><strong>Inline_executor semantics:<\/strong> If the shared state is ready when the continuation is set, the consumer thread executes the continuation. If the shared state is not ready when the continuation is set, the producer thread executes the continuation.<\/li>\n<li><strong>thread_executor semantics<\/strong>: A new <span style=\"font-family: 'courier new', courier;\">std::thread<\/span> executes the continuation.<\/li>\n<\/ol>\n<p>In particular, the first two possibilities have a significant drawback: they block. In the first case, the consumer blocks until the producer is ready. In the second case, the producer blocks until the consumer is ready.<\/p>\n<p>Here are a few nice use cases of executor propagation from the document P0701r184:<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">auto<\/span> i <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>async(thread_pool, f).then(g).then(h);\r\n<span style=\"color: #0099ff; font-style: italic;\">\/\/ f, g and h are executed on thread_pool.<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> i <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>async(thread_pool, f).then(g, gpu).then(h);\r\n<span style=\"color: #0099ff; font-style: italic;\">\/\/ f is executed on thread_pool, g and h are executed on gpu.<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> i <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>async(inline_executor, f).then(g).then(h);\r\n<span style=\"color: #0099ff; font-style: italic;\">\/\/ h(g(f())) are invoked in the calling execution agent.<\/span>\r\n<\/pre>\n<\/div>\n<h4>Passing futures to<span style=\"font-family: courier new, courier;\"> .then<\/span> Continuations is Unwieldy<\/h4>\n<p>Because the future is passed to the continuation and not its value, the syntax is quite complicated.<br \/>First, the correct but verbose version.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std<span style=\"color: #555555;\">::<\/span>future f1 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>async([]() { <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">123<\/span>; });\r\nstd<span style=\"color: #555555;\">::<\/span>future f2 <span style=\"color: #555555;\">=<\/span> f1.then([](std<span style=\"color: #555555;\">::<\/span>future f) {\r\n    <span style=\"color: #006699; font-weight: bold;\">return<\/span> std<span style=\"color: #555555;\">::<\/span>to_string(f.get());\r\n});\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Now, I assume that I can pass the value because <span style=\"font-family: courier new, courier;\">to_string<\/span> is overloaded on <span style=\"font-family: courier new, courier;\">std::future<\/span>.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std<span style=\"color: #555555;\">::<\/span>future f1 <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>async([]() { <span style=\"color: #006699; font-weight: bold;\">return<\/span> <span style=\"color: #ff6600;\">123<\/span>; });\r\nstd<span style=\"color: #555555;\">::<\/span>future f2 <span style=\"color: #555555;\">=<\/span> f1.then(std<span style=\"color: #555555;\">::<\/span>to_string);\r\n<\/pre>\n<\/div>\n<h4><span style=\"font-family: courier new, courier;\">when_all<\/span> and <span style=\"font-family: courier new, courier;\">when_any<\/span> Return Types are Unwieldy<\/h4>\n<p>The post <a href=\"https:\/\/www.modernescpp.com\/index.php\/std-future-extensions\"><span style=\"font-family: courier new, courier;\">std::future Extensions<\/span><\/a> show the quite complicated usage of <span style=\"font-family: courier new, courier;\">when_all<\/span> and <span style=\"font-family: courier new, courier;\">when_any.<\/span><\/p>\n<h4>Conditional Blocking in futures Destructor Must Go<\/h4>\n<p>Fire and forget futures look very promising but have significant drawbacks. A future created by <span style=\"font-family: courier new, courier;\">std::async<\/span> waits on its destructor until its promise is done. What seems to be concurrent runs sequentially. According to document P0701r1, this is not acceptable and error-prone.<\/p>\n<p>I describe the peculiar behavior of fire and forget futures in the post <a href=\"https:\/\/www.modernescpp.com\/index.php\/the-special-futures\">The Special Futures<\/a>.<\/p>\n<h4>Immediate Values and future Values Should Be Easily Composable<\/h4>\n<p>In C++11, there is no convenient way to create a future. We have to start with a promise.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std<span style=\"color: #555555;\">::<\/span>promise<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> p;\r\nstd<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> fut <span style=\"color: #555555;\">=<\/span> p.get_future();\r\np.set_value(<span style=\"color: #cc3300;\">\"hello\"<\/span>);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>This may change with the function <span style=\"font-family: courier new, courier;\">std::make_ready_future<\/span>&nbsp;from the concurrency TS v1.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> fut <span style=\"color: #555555;\">=<\/span> make_ready_future(<span style=\"color: #cc3300;\">\"hello\"<\/span>);\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Using future and non-future arguments would make our job even more comfortable.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007788; font-weight: bold;\">bool<\/span> <span style=\"color: #cc00ff;\">f<\/span>(std<span style=\"color: #555555;\">::<\/span>string, <span style=\"color: #007788; font-weight: bold;\">double<\/span>, <span style=\"color: #007788; font-weight: bold;\">int<\/span>);\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&gt;<\/span> a <span style=\"color: #555555;\">=<\/span> <span style=\"color: #0099ff; font-style: italic;\">\/* ... *\/<\/span>;\r\nstd<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> c <span style=\"color: #555555;\">=<\/span> <span style=\"color: #0099ff; font-style: italic;\">\/* ... *\/<\/span>;\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">bool<\/span><span style=\"color: #555555;\">&gt;<\/span> d1 <span style=\"color: #555555;\">=<\/span> when_all(a, make_ready_future(<span style=\"color: #ff6600;\">3.14<\/span>), c).then(f);\r\n<span style=\"color: #0099ff; font-style: italic;\">\/\/ f(a.get(), 3.14, c.get())<\/span>\r\n\r\nstd<span style=\"color: #555555;\">::<\/span>future<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">bool<\/span><span style=\"color: #555555;\">&gt;<\/span> d2 <span style=\"color: #555555;\">=<\/span> when_all(a, <span style=\"color: #ff6600;\">3.14<\/span>, c).then(f);\r\n<span style=\"color: #0099ff; font-style: italic;\">\/\/ f(a.get(), 3.14, c.get())<\/span>\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Neither the syntactic form <span style=\"font-family: courier new, courier;\">d1<\/span> nor the syntactic form <span style=\"font-family: courier new, courier;\">d2<\/span> is possible with the concurrency TS.<\/p>\n<h3>Five New Concepts<\/h3>\n<p>There are five new concepts for futures and promises in Proposal <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2018\/p1054r0.html\">1054R085<\/a> to unified futures.<\/p>\n<ul>\n<li><strong> FutureContinuation<\/strong>, is invocable objects that are called with the value or exception of a future as an argument.<\/li>\n<li><strong>SemiFuture<\/strong>, which can be bound to an executor, an operation that produces a <strong>ContinuableFuture<\/strong> (<span style=\"font-family: 'courier new', courier;\">f = sf.via(exec)<\/span>).&nbsp;<\/li>\n<li><strong>ContinuableFuture<\/strong>, which refines <strong>SemiFuture<\/strong> and instances, can have one <strong>FutureContinuation<\/strong> c attached to them (<span style=\"font-family: 'courier new', courier;\">f.then(c)<\/span>), executed on the future associated executor when the future f becomes ready.<\/li>\n<li><strong> SharedFuture<\/strong>, which refines <strong>ContinuableFuture<\/strong>, and instances can have multiple <strong>FutureContinuations<\/strong> attached to them.<\/li>\n<li><strong> Promise<\/strong>, each of which is associated with a future and prepares the future with either a value or an exception.<\/li>\n<\/ul>\n<p>The paper also provides the declaration of these new concepts:<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> FutureContinuation\r\n{\r\n  <span style=\"color: #0099ff; font-style: italic;\">\/\/ At least one of these two overloads exists:<\/span>\r\n  <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span>()(T value);\r\n  <span style=\"color: #006699; font-weight: bold;\">auto<\/span> <span style=\"color: #cc00ff;\">operator<\/span>()(<span style=\"color: #007788; font-weight: bold;\">exception_arg_t<\/span>, exception_ptr exception);\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> SemiFuture\r\n{\r\n  <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Executor<span style=\"color: #555555;\">&gt;<\/span>\r\n  ContinuableFuture<span style=\"color: #555555;\">&lt;<\/span>Executor, T<span style=\"color: #555555;\">&gt;<\/span> via(Executor<span style=\"color: #555555;\">&amp;&amp;<\/span> exec) <span style=\"color: #555555;\">&amp;&amp;<\/span>;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Executor, <span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> ContinuableFuture\r\n{\r\n  <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> RExecutor<span style=\"color: #555555;\">&gt;<\/span>\r\n  ContinuableFuture<span style=\"color: #555555;\">&lt;<\/span>RExecutor, T<span style=\"color: #555555;\">&gt;<\/span> via(RExecutor<span style=\"color: #555555;\">&amp;&amp;<\/span> exec) <span style=\"color: #555555;\">&amp;&amp;<\/span>;\r\n\r\n  <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Continuation<span style=\"color: #555555;\">&gt;<\/span>\r\n  ContinuableFuture<span style=\"color: #555555;\">&lt;<\/span>Executor, <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&gt;<\/span> then(Continuation<span style=\"color: #555555;\">&amp;&amp;<\/span> c) <span style=\"color: #555555;\">&amp;&amp;<\/span>;\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Executor, <span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> SharedFuture\r\n{\r\n  <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> RExecutor<span style=\"color: #555555;\">&gt;<\/span>\r\n  ContinuableFuture<span style=\"color: #555555;\">&lt;<\/span>RExecutor, <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&gt;<\/span> via(RExecutor<span style=\"color: #555555;\">&amp;&amp;<\/span> exec);\r\n\r\n  <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Continuation<span style=\"color: #555555;\">&gt;<\/span>\r\n  SharedFuture<span style=\"color: #555555;\">&lt;<\/span>Executor, <span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&gt;<\/span> then(Continuation<span style=\"color: #555555;\">&amp;&amp;<\/span> c);\r\n};\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #006699; font-weight: bold;\">struct<\/span> Promise\r\n{\r\n  <span style=\"color: #007788; font-weight: bold;\">void<\/span> set_value(T value) <span style=\"color: #555555;\">&amp;&amp;<\/span>;\r\n\r\n  <span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> Error<span style=\"color: #555555;\">&gt;<\/span>\r\n  <span style=\"color: #007788; font-weight: bold;\">void<\/span> set_exception(Error exception) <span style=\"color: #555555;\">&amp;&amp;<\/span>;\r\n  <span style=\"color: #007788; font-weight: bold;\">bool<\/span> valid() <span style=\"color: #006699; font-weight: bold;\">const<\/span>;\r\n};\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Based on the declaration of the concepts, here are a few observations:<\/p>\n<ul>\n<li>A <span style=\"font-family: courier new, courier;\">FutureContinuatio<\/span>n can be invoked with a value or with an exception.<\/li>\n<li>All futures (<span style=\"font-family: courier new, courier;\">SemiFuture, ContinuableFuture<\/span>, and <span style=\"font-family: courier new, courier;\">SharedFuture<\/span>) have a method that excepts an executor and returns a ContinuableFuture. <span style=\"font-family: courier new, courier;\">via<\/span> allows it to convert from one future type to a different one using a different executor.<\/li>\n<li>Only a ContinuableFuture or a SharedFuture has a <span style=\"font-family: courier new, courier;\">then<\/span> continuation method. The <span style=\"font-family: 'courier new', courier;\">then<\/span> method takes a <span style=\"font-family: courier new, courier;\">FutureContinuation<\/span> and returns a ContinuableFuture.<\/li>\n<li>A <span style=\"font-family: courier new, courier;\">Promise<\/span> can set a value or an exception.<\/li>\n<\/ul>\n<h3>Future Work<\/h3>\n<p>Proposal <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2018\/p1054r0.html\">1054R086<\/a> left a few questions open.<\/p>\n<ul>\n<li>Forward progress guarantees futures and promises.<\/li>\n<li>Requirements on synchronization for using futures and promises from non-concurrent execution agents.<\/li>\n<li><span style=\"font-family: 'courier new', courier;\"><\/span>Interoperability with the standardized <span style=\"font-family: 'courier new', courier;\">std::future<\/span> and <span style=\"font-family: 'courier new', courier;\">std::promise<\/span><span style=\"font-family: 'courier new', courier;\">.<\/span><\/li>\n<li>Future unwrapping, both <span style=\"font-family: courier new, courier;\">future&lt;future&gt;<\/span> and more advanced forms. Future unwrapping should, in the concrete case, remove the outer future.<\/li>\n<li>Implementation of<span style=\"font-family: courier new, courier;\"> when_all, when_any, <\/span>or<span style=\"font-family: courier new, courier;\"> when_n.<\/span><\/li>\n<li>Interoperability with<span style=\"font-family: courier new, courier;\"> std::async.<\/span><\/li>\n<\/ul>\n<p>I promise I will write about them in the future.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>My next post continues with my journey through the C++ core guidelines. This time I write about lock-free programming.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>After the last post to executors, I can finally write about the unified futures. I write in the post about the long past of the futures and end my detour from the C++ core guidelines.<\/p>\n","protected":false},"author":21,"featured_media":5454,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[367],"tags":[484,482,446],"class_list":["post-5455","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-multithreading-c-17-and-c-20","tag-executors","tag-outdated","tag-tasks"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5455","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5455"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5455\/revisions"}],"predecessor-version":[{"id":6823,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5455\/revisions\/6823"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5454"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5455"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5455"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5455"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}