]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/fiber/doc/html/fiber/when_any/when_any/when_any__produce_first_outcome__whether_result_or_exception.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / fiber / doc / html / fiber / when_any / when_any / when_any__produce_first_outcome__whether_result_or_exception.html
CommitLineData
7c673cae
FG
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
4<title>when_any, produce first outcome, whether result or exception</title>
5<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
7<link rel="home" href="../../../index.html" title="Chapter&#160;1.&#160;Fiber">
8<link rel="up" href="../when_any.html" title="when_any">
9<link rel="prev" href="when_any__return_value.html" title="when_any, return value">
10<link rel="next" href="when_any__produce_first_success.html" title="when_any, produce first success">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%"><tr>
14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
15<td align="center"><a href="../../../../../../../index.html">Home</a></td>
16<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
19<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
20</tr></table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="when_any__return_value.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../when_any.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="when_any__produce_first_success.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
24</div>
25<div class="section">
26<div class="titlepage"><div><div><h4 class="title">
27<a name="fiber.when_any.when_any.when_any__produce_first_outcome__whether_result_or_exception"></a><a class="link" href="when_any__produce_first_outcome__whether_result_or_exception.html" title="when_any, produce first outcome, whether result or exception">when_any,
28 produce first outcome, whether result or exception</a>
29</h4></div></div></div>
30<p>
31 We may not be running in an environment in which we can guarantee no exception
32 will be thrown by any of our task functions. In that case, the above implementations
33 of <code class="computeroutput"><span class="identifier">wait_first_something</span><span class="special">()</span></code> would be na&#239;ve: as mentioned in <a class="link" href="../../fiber_mgmt.html#exceptions">the section on Fiber Management</a>, an uncaught
34 exception in one of our task fibers would cause <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">terminate</span><span class="special">()</span></code> to be called.
35 </p>
36<p>
37 Let's at least ensure that such an exception would propagate to the fiber
38 awaiting the first result. We can use <a class="link" href="../../synchronization/futures/future.html#class_future"><code class="computeroutput">future&lt;&gt;</code></a> to transport
39 either a return value or an exception. Therefore, we will change <a class="link" href="when_any__return_value.html#wait_first_value"><code class="computeroutput"><span class="identifier">wait_first_value</span><span class="special">()</span></code></a>'s <a class="link" href="../../synchronization/channels.html#class_unbounded_channel"><code class="computeroutput">unbounded_channel&lt;&gt;</code></a> to
40 hold <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;</span>
41 <span class="identifier">T</span> <span class="special">&gt;</span></code>
42 items instead of simply <code class="computeroutput"><span class="identifier">T</span></code>.
43 </p>
44<p>
45 Once we have a <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
46 in hand, all we need do is call <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a>, which will either
47 return the value or rethrow the exception.
48 </p>
49<p>
50 <a name="wait_first_outcome"></a>
51</p>
52<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">Fn</span><span class="special">,</span> <span class="keyword">typename</span> <span class="special">...</span> <span class="identifier">Fns</span> <span class="special">&gt;</span>
53<span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">&lt;</span> <span class="identifier">Fn</span><span class="special">()</span> <span class="special">&gt;::</span><span class="identifier">type</span>
54<span class="identifier">wait_first_outcome</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">function</span><span class="special">,</span> <span class="identifier">Fns</span> <span class="special">&amp;&amp;</span> <span class="special">...</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">{</span>
55 <span class="comment">// In this case, the value we pass through the channel is actually a</span>
56 <span class="comment">// future -- which is already ready. future can carry either a value or an</span>
57 <span class="comment">// exception.</span>
58 <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of</span><span class="special">&lt;</span> <span class="identifier">Fn</span><span class="special">()</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">return_t</span><span class="special">;</span>
59 <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">future</span><span class="special">&lt;</span> <span class="identifier">return_t</span> <span class="special">&gt;</span> <span class="identifier">future_t</span><span class="special">;</span>
60 <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">unbounded_channel</span><span class="special">&lt;</span> <span class="identifier">future_t</span> <span class="special">&gt;</span> <span class="identifier">channel_t</span><span class="special">;</span>
61 <span class="keyword">auto</span> <span class="identifier">channelp</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">channel_t</span> <span class="special">&gt;()</span> <span class="special">);</span>
62 <span class="comment">// launch all the relevant fibers</span>
63 <span class="identifier">wait_first_outcome_impl</span><span class="special">&lt;</span> <span class="identifier">return_t</span> <span class="special">&gt;(</span> <span class="identifier">channelp</span><span class="special">,</span>
64 <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span> <span class="identifier">Fn</span> <span class="special">&gt;(</span> <span class="identifier">function</span><span class="special">),</span>
65 <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span> <span class="identifier">Fns</span> <span class="special">&gt;(</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">...</span> <span class="special">);</span>
66 <span class="comment">// retrieve the first future</span>
67 <span class="identifier">future_t</span> <span class="identifier">future</span><span class="special">(</span> <span class="identifier">channelp</span><span class="special">-&gt;</span><span class="identifier">value_pop</span><span class="special">()</span> <span class="special">);</span>
68 <span class="comment">// close the channel: no subsequent push() has to succeed</span>
69 <span class="identifier">channelp</span><span class="special">-&gt;</span><span class="identifier">close</span><span class="special">();</span>
70 <span class="comment">// either return value or throw exception</span>
71 <span class="keyword">return</span> <span class="identifier">future</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
72<span class="special">}</span>
73</pre>
74<p>
75 </p>
76<p>
77 So far so good &#8212; but there's a timing issue. How should we obtain the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
78 to <a class="link" href="../../synchronization/channels.html#unbounded_channel_push"><code class="computeroutput">unbounded_channel::push()</code></a> on the channel?
79 </p>
80<p>
81 We could call <a class="link" href="../../synchronization/futures/future.html#fibers_async"><code class="computeroutput">fibers::async()</code></a>. That would certainly produce
82 a <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
83 for the task function. The trouble is that it would return too quickly!
84 We only want <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
85 items for <span class="emphasis"><em>completed</em></span> tasks on our <code class="computeroutput"><span class="identifier">unbounded_channel</span><span class="special">&lt;&gt;</span></code>. In fact, we only want the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
86 for the one that completes first. If each fiber launched by <code class="computeroutput"><span class="identifier">wait_first_outcome</span><span class="special">()</span></code>
87 were to <code class="computeroutput"><span class="identifier">push</span><span class="special">()</span></code>
88 the result of calling <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>, the channel would only ever report the
89 result of the leftmost task item &#8212; <span class="emphasis"><em>not</em></span> the one that
90 completes most quickly.
91 </p>
92<p>
93 Calling <a class="link" href="../../synchronization/futures/future.html#future_get"><code class="computeroutput">future::get()</code></a> on the future returned by <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
94 wouldn't be right. You can only call <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code> once per <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code> instance! And if there were an
95 exception, it would be rethrown inside the helper fiber at the producer
96 end of the channel, rather than propagated to the consumer end.
97 </p>
98<p>
99 We could call <a class="link" href="../../synchronization/futures/future.html#future_wait"><code class="computeroutput">future::wait()</code></a>. That would block the helper fiber
100 until the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
101 became ready, at which point we could <code class="computeroutput"><span class="identifier">push</span><span class="special">()</span></code> it to be retrieved by <code class="computeroutput"><span class="identifier">wait_first_outcome</span><span class="special">()</span></code>.
102 </p>
103<p>
104 That would work &#8212; but there's a simpler tactic that avoids creating an extra
105 fiber. We can wrap the task function in a <a class="link" href="../../synchronization/futures/packaged_task.html#class_packaged_task"><code class="computeroutput">packaged_task&lt;&gt;</code></a>.
106 While one naturally thinks of passing a <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code> to a new fiber &#8212; that is, in fact,
107 what <code class="computeroutput"><span class="identifier">async</span><span class="special">()</span></code>
108 does &#8212; in this case, we're already running in the helper fiber at the producer
109 end of the channel! We can simply <span class="emphasis"><em>call</em></span> the <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code>.
110 On return from that call, the task function has completed, meaning that
111 the <code class="computeroutput"><span class="identifier">future</span><span class="special">&lt;&gt;</span></code>
112 obtained from the <code class="computeroutput"><span class="identifier">packaged_task</span><span class="special">&lt;&gt;</span></code> is certain to be ready. At that
113 point we can simply <code class="computeroutput"><span class="identifier">push</span><span class="special">()</span></code> it to the channel.
114 </p>
115<p>
116 <a name="wait_first_outcome_impl"></a>
117</p>
118<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">CHANNELP</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Fn</span> <span class="special">&gt;</span>
119<span class="keyword">void</span> <span class="identifier">wait_first_outcome_impl</span><span class="special">(</span> <span class="identifier">CHANNELP</span> <span class="identifier">channel</span><span class="special">,</span> <span class="identifier">Fn</span> <span class="special">&amp;&amp;</span> <span class="identifier">function</span><span class="special">)</span> <span class="special">{</span>
120 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">fiber</span><span class="special">(</span>
121 <span class="comment">// Use std::bind() here for C++11 compatibility. C++11 lambda capture</span>
122 <span class="comment">// can't move a move-only Fn type, but bind() can. Let bind() move the</span>
123 <span class="comment">// channel pointer and the function into the bound object, passing</span>
124 <span class="comment">// references into the lambda.</span>
125 <span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span>
126 <span class="special">[](</span> <span class="identifier">CHANNELP</span> <span class="special">&amp;</span> <span class="identifier">channel</span><span class="special">,</span>
127 <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay</span><span class="special">&lt;</span> <span class="identifier">Fn</span> <span class="special">&gt;::</span><span class="identifier">type</span> <span class="special">&amp;</span> <span class="identifier">function</span><span class="special">)</span> <span class="special">{</span>
128 <span class="comment">// Instantiate a packaged_task to capture any exception thrown by</span>
129 <span class="comment">// function.</span>
130 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">packaged_task</span><span class="special">&lt;</span> <span class="identifier">T</span><span class="special">()</span> <span class="special">&gt;</span> <span class="identifier">task</span><span class="special">(</span> <span class="identifier">function</span><span class="special">);</span>
131 <span class="comment">// Immediately run this packaged_task on same fiber. We want</span>
132 <span class="comment">// function() to have completed BEFORE we push the future.</span>
133 <span class="identifier">task</span><span class="special">();</span>
134 <span class="comment">// Pass the corresponding future to consumer. Ignore</span>
135 <span class="comment">// channel_op_status returned by push(): might be closed; we</span>
136 <span class="comment">// simply don't care.</span>
137 <span class="identifier">channel</span><span class="special">-&gt;</span><span class="identifier">push</span><span class="special">(</span> <span class="identifier">task</span><span class="special">.</span><span class="identifier">get_future</span><span class="special">()</span> <span class="special">);</span>
138 <span class="special">},</span>
139 <span class="identifier">channel</span><span class="special">,</span>
140 <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special">&lt;</span> <span class="identifier">Fn</span> <span class="special">&gt;(</span> <span class="identifier">function</span><span class="special">)</span>
141 <span class="special">)).</span><span class="identifier">detach</span><span class="special">();</span>
142<span class="special">}</span>
143</pre>
144<p>
145 </p>
146<p>
147 Calling it might look like this:
148 </p>
149<p>
150</p>
151<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">wait_first_outcome</span><span class="special">(</span>
152 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wfos_first"</span><span class="special">,</span> <span class="number">50</span><span class="special">);</span> <span class="special">},</span>
153 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wfos_second"</span><span class="special">,</span> <span class="number">100</span><span class="special">);</span> <span class="special">},</span>
154 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wfos_third"</span><span class="special">,</span> <span class="number">150</span><span class="special">);</span> <span class="special">});</span>
155<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"wait_first_outcome(success) =&gt; "</span> <span class="special">&lt;&lt;</span> <span class="identifier">result</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
156<span class="identifier">assert</span><span class="special">(</span><span class="identifier">result</span> <span class="special">==</span> <span class="string">"wfos_first"</span><span class="special">);</span>
157
158<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">thrown</span><span class="special">;</span>
159<span class="keyword">try</span> <span class="special">{</span>
160 <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">wait_first_outcome</span><span class="special">(</span>
161 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wfof_first"</span><span class="special">,</span> <span class="number">50</span><span class="special">,</span> <span class="keyword">true</span><span class="special">);</span> <span class="special">},</span>
162 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wfof_second"</span><span class="special">,</span> <span class="number">100</span><span class="special">);</span> <span class="special">},</span>
163 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wfof_third"</span><span class="special">,</span> <span class="number">150</span><span class="special">);</span> <span class="special">});</span>
164<span class="special">}</span> <span class="keyword">catch</span> <span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span> <span class="special">{</span>
165 <span class="identifier">thrown</span> <span class="special">=</span> <span class="identifier">e</span><span class="special">.</span><span class="identifier">what</span><span class="special">();</span>
166<span class="special">}</span>
167<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"wait_first_outcome(fail) threw '"</span> <span class="special">&lt;&lt;</span> <span class="identifier">thrown</span>
168 <span class="special">&lt;&lt;</span> <span class="string">"'"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
169<span class="identifier">assert</span><span class="special">(</span><span class="identifier">thrown</span> <span class="special">==</span> <span class="string">"wfof_first"</span><span class="special">);</span>
170</pre>
171<p>
172 </p>
173</div>
174<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
175<td align="left"></td>
176<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
177 Distributed under the Boost Software License, Version 1.0. (See accompanying
178 file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
179 </p>
180</div></td>
181</tr></table>
182<hr>
183<div class="spirit-nav">
184<a accesskey="p" href="when_any__return_value.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../when_any.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="when_any__produce_first_success.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
185</div>
186</body>
187</html>