3 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
4 <title>when_all, return values</title>
5 <link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
6 <meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
7 <link rel="home" href="../../../index.html" title="Chapter 1. Fiber">
8 <link rel="up" href="../when_all_functionality.html" title="when_all functionality">
9 <link rel="prev" href="when_all__simple_completion.html" title="when_all, simple completion">
10 <link rel="next" href="when_all_until_first_exception.html" title="when_all until first exception">
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>
22 <div class="spirit-nav">
23 <a accesskey="p" href="when_all__simple_completion.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../when_all_functionality.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_all_until_first_exception.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
26 <div class="titlepage"><div><div><h4 class="title">
27 <a name="fiber.when_any.when_all_functionality.when_all__return_values"></a><a class="link" href="when_all__return_values.html" title="when_all, return values">when_all,
29 </h4></div></div></div>
31 As soon as we want to collect return values from all the task functions,
32 we can see right away how to reuse <a class="link" href="../when_any/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
33 queue<T> for the purpose. All we have to do is avoid closing it after
37 But in fact, collecting multiple values raises an interesting question:
38 do we <span class="emphasis"><em>really</em></span> want to wait until the slowest of them
39 has arrived? Wouldn't we rather process each result as soon as it becomes
43 Fortunately we can present both APIs. Let's define <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code> to return <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special"><</span><span class="identifier">buffered_channel</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></span></code>.
46 <a name="wait_all_values"></a>Given <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code>, it's straightforward to implement <code class="computeroutput"><span class="identifier">wait_all_values</span><span class="special">()</span></code>:
50 <pre class="programlisting"><span class="keyword">template</span><span class="special"><</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">></span>
51 <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span> <span class="identifier">Fn</span><span class="special">()</span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span>
52 <span class="identifier">wait_all_values</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&&</span> <span class="identifier">function</span><span class="special">,</span> <span class="identifier">Fns</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">{</span>
53 <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">count</span><span class="special">(</span> <span class="number">1</span> <span class="special">+</span> <span class="keyword">sizeof</span> <span class="special">...</span> <span class="special">(</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">);</span>
54 <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"><</span> <span class="identifier">Fn</span><span class="special">()</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">return_t</span><span class="special">;</span>
55 <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span> <span class="identifier">return_t</span> <span class="special">></span> <span class="identifier">vector_t</span><span class="special">;</span>
56 <span class="identifier">vector_t</span> <span class="identifier">results</span><span class="special">;</span>
57 <span class="identifier">results</span><span class="special">.</span><span class="identifier">reserve</span><span class="special">(</span> <span class="identifier">count</span><span class="special">);</span>
59 <span class="comment">// get channel</span>
60 <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">buffered_channel</span><span class="special"><</span> <span class="identifier">return_t</span> <span class="special">></span> <span class="special">></span> <span class="identifier">chan</span> <span class="special">=</span>
61 <span class="identifier">wait_all_values_source</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special"><</span> <span class="identifier">Fn</span> <span class="special">>(</span> <span class="identifier">function</span><span class="special">),</span>
62 <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special"><</span> <span class="identifier">Fns</span> <span class="special">>(</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">...</span> <span class="special">);</span>
63 <span class="comment">// fill results vector</span>
64 <span class="identifier">return_t</span> <span class="identifier">value</span><span class="special">;</span>
65 <span class="keyword">while</span> <span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">channel_op_status</span><span class="special">::</span><span class="identifier">success</span> <span class="special">==</span> <span class="identifier">chan</span><span class="special">-></span><span class="identifier">pop</span><span class="special">(</span><span class="identifier">value</span><span class="special">)</span> <span class="special">)</span> <span class="special">{</span>
66 <span class="identifier">results</span><span class="special">.</span><span class="identifier">push_back</span><span class="special">(</span> <span class="identifier">value</span><span class="special">);</span>
67 <span class="special">}</span>
68 <span class="comment">// return vector to caller</span>
69 <span class="keyword">return</span> <span class="identifier">results</span><span class="special">;</span>
70 <span class="special">}</span>
75 It might be called like this:
79 <pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">vector</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="identifier">values</span> <span class="special">=</span>
80 <span class="identifier">wait_all_values</span><span class="special">(</span>
81 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wav_late"</span><span class="special">,</span> <span class="number">150</span><span class="special">);</span> <span class="special">},</span>
82 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wav_middle"</span><span class="special">,</span> <span class="number">100</span><span class="special">);</span> <span class="special">},</span>
83 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wav_early"</span><span class="special">,</span> <span class="number">50</span><span class="special">);</span> <span class="special">});</span>
88 As you can see from the loop in <code class="computeroutput"><span class="identifier">wait_all_values</span><span class="special">()</span></code>, instead of requiring its caller to count
89 values, we define <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code> to <a class="link" href="../../synchronization/channels/buffered_channel.html#buffered_channel_close"><code class="computeroutput">buffered_channel::close()</code></a> the
90 queue when done. But how do we do that? Each producer fiber is independent.
91 It has no idea whether it is the last one to <a class="link" href="../../synchronization/channels/buffered_channel.html#buffered_channel_push"><code class="computeroutput">buffered_channel::push()</code></a> a
95 <a name="wait_nqueue"></a>We can address that problem with a counting façade
96 for the <code class="computeroutput"><span class="identifier">queue</span><span class="special"><></span></code>.
97 In fact, our façade need only support the producer end of the queue.
103 <a name="wait_all_values_source"></a>Armed with <code class="computeroutput"><span class="identifier">nqueue</span><span class="special"><></span></code>, we can implement <code class="computeroutput"><span class="identifier">wait_all_values_source</span><span class="special">()</span></code>.
104 It starts just like <a class="link" href="../when_any/when_any__return_value.html#wait_first_value"><code class="computeroutput"><span class="identifier">wait_first_value</span><span class="special">()</span></code></a>. The difference is that we wrap
105 the <code class="computeroutput"><span class="identifier">queue</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code>
106 with an <code class="computeroutput"><span class="identifier">nqueue</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code>
107 to pass to the producer fibers.
110 Then, of course, instead of popping the first value, closing the queue
111 and returning it, we simply return the <code class="computeroutput"><span class="identifier">shared_ptr</span><span class="special"><</span><span class="identifier">queue</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></span></code>.
115 <pre class="programlisting"><span class="comment">// Return a shared_ptr<buffered_channel<T>> from which the caller can</span>
116 <span class="comment">// retrieve each new result as it arrives, until 'closed'.</span>
117 <span class="keyword">template</span><span class="special"><</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">></span>
118 <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">buffered_channel</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">result_of</span><span class="special"><</span> <span class="identifier">Fn</span><span class="special">()</span> <span class="special">>::</span><span class="identifier">type</span> <span class="special">></span> <span class="special">></span>
119 <span class="identifier">wait_all_values_source</span><span class="special">(</span> <span class="identifier">Fn</span> <span class="special">&&</span> <span class="identifier">function</span><span class="special">,</span> <span class="identifier">Fns</span> <span class="special">&&</span> <span class="special">...</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">{</span>
120 <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">count</span><span class="special">(</span> <span class="number">1</span> <span class="special">+</span> <span class="keyword">sizeof</span> <span class="special">...</span> <span class="special">(</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">);</span>
121 <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"><</span> <span class="identifier">Fn</span><span class="special">()</span> <span class="special">>::</span><span class="identifier">type</span> <span class="identifier">return_t</span><span class="special">;</span>
122 <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">buffered_channel</span><span class="special"><</span> <span class="identifier">return_t</span> <span class="special">></span> <span class="identifier">channel_t</span><span class="special">;</span>
123 <span class="comment">// make the channel</span>
124 <span class="keyword">auto</span> <span class="identifier">chanp</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">channel_t</span> <span class="special">>(</span> <span class="number">64</span><span class="special">)</span> <span class="special">);</span>
125 <span class="comment">// and make an nchannel facade to close it after 'count' items</span>
126 <span class="keyword">auto</span> <span class="identifier">ncp</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">nchannel</span><span class="special"><</span> <span class="identifier">return_t</span> <span class="special">></span> <span class="special">>(</span> <span class="identifier">chanp</span><span class="special">,</span> <span class="identifier">count</span><span class="special">)</span> <span class="special">);</span>
127 <span class="comment">// pass that nchannel facade to all the relevant fibers</span>
128 <span class="identifier">wait_all_values_impl</span><span class="special"><</span> <span class="identifier">return_t</span> <span class="special">>(</span> <span class="identifier">ncp</span><span class="special">,</span>
129 <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special"><</span> <span class="identifier">Fn</span> <span class="special">>(</span> <span class="identifier">function</span><span class="special">),</span>
130 <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward</span><span class="special"><</span> <span class="identifier">Fns</span> <span class="special">>(</span> <span class="identifier">functions</span><span class="special">)</span> <span class="special">...</span> <span class="special">);</span>
131 <span class="comment">// then return the channel for consumer</span>
132 <span class="keyword">return</span> <span class="identifier">chanp</span><span class="special">;</span>
133 <span class="special">}</span>
142 <pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">buffered_channel</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="special">></span> <span class="identifier">chan</span> <span class="special">=</span>
143 <span class="identifier">wait_all_values_source</span><span class="special">(</span>
144 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wavs_third"</span><span class="special">,</span> <span class="number">150</span><span class="special">);</span> <span class="special">},</span>
145 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wavs_second"</span><span class="special">,</span> <span class="number">100</span><span class="special">);</span> <span class="special">},</span>
146 <span class="special">[](){</span> <span class="keyword">return</span> <span class="identifier">sleeper</span><span class="special">(</span><span class="string">"wavs_first"</span><span class="special">,</span> <span class="number">50</span><span class="special">);</span> <span class="special">});</span>
147 <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">value</span><span class="special">;</span>
148 <span class="keyword">while</span> <span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">channel_op_status</span><span class="special">::</span><span class="identifier">success</span> <span class="special">==</span> <span class="identifier">chan</span><span class="special">-></span><span class="identifier">pop</span><span class="special">(</span><span class="identifier">value</span><span class="special">)</span> <span class="special">)</span> <span class="special">{</span>
149 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"wait_all_values_source() => '"</span> <span class="special"><<</span> <span class="identifier">value</span>
150 <span class="special"><<</span> <span class="string">"'"</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
151 <span class="special">}</span>
156 <a name="wait_all_values_impl"></a><code class="computeroutput"><span class="identifier">wait_all_values_impl</span><span class="special">()</span></code> really is just like <a class="link" href="../when_any/when_any__return_value.html#wait_first_value_impl"><code class="computeroutput"><span class="identifier">wait_first_value_impl</span><span class="special">()</span></code></a>
157 except for the use of <code class="computeroutput"><span class="identifier">nqueue</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code> rather than <code class="computeroutput"><span class="identifier">queue</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code>:
161 <pre class="programlisting"><span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">Fn</span> <span class="special">></span>
162 <span class="keyword">void</span> <span class="identifier">wait_all_values_impl</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">nchannel</span><span class="special"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">></span> <span class="identifier">chan</span><span class="special">,</span>
163 <span class="identifier">Fn</span> <span class="special">&&</span> <span class="identifier">function</span><span class="special">)</span> <span class="special">{</span>
164 <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> <span class="special">[</span><span class="identifier">chan</span><span class="special">,</span> <span class="identifier">function</span><span class="special">](){</span>
165 <span class="identifier">chan</span><span class="special">-></span><span class="identifier">push</span><span class="special">(</span><span class="identifier">function</span><span class="special">());</span>
166 <span class="special">}).</span><span class="identifier">detach</span><span class="special">();</span>
167 <span class="special">}</span>
172 <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
173 <td align="left"></td>
174 <td align="right"><div class="copyright-footer">Copyright © 2013 Oliver Kowalke<p>
175 Distributed under the Boost Software License, Version 1.0. (See accompanying
176 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>)
181 <div class="spirit-nav">
182 <a accesskey="p" href="when_all__simple_completion.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../when_all_functionality.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_all_until_first_exception.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>