Boost C++ Libraries: Ticket #12293: boost::future::then lambda called before future is ready. https://svn.boost.org/trac10/ticket/12293 <p> When chaining .then together with anther one and the previous .then returns a boost::future. The lambda will get called before the future is ready. I think what is happening is that the lambda is being called when the outer hidden future is ready. I think that the callback shouldn't be called until the returned future is ready. </p> <p> Here is the sample code which demonstrates the problem. </p> <div class="wiki-code"><div class="code"><pre><span class="c1">// BoostFutureTest.cpp : Defines the entry point for the console application.</span> <span class="c1">//</span> <span class="cp">#include</span> <span class="cpf">&quot;stdafx.h&quot;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;future&gt;</span><span class="cp"></span> <span class="c1">// boost version 1.60.0</span> <span class="c1">// has the following set.</span> <span class="c1">// #define BOOST_THREAD_VERSION 4</span> <span class="c1">// #define BOOST_THREAD_PROVIDES_EXECUTORS</span> <span class="cp">#include</span> <span class="cpf">&lt;boost\thread\future.hpp&gt;</span><span class="cp"></span> <span class="kt">int</span> <span class="nf">_tmain</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="n">_TCHAR</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="kt">int</span> <span class="n">tmpValue</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">boost</span><span class="o">::</span><span class="n">promise</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="n">promise1</span><span class="p">;</span> <span class="n">boost</span><span class="o">::</span><span class="n">promise</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="n">promise2</span><span class="p">;</span> <span class="k">auto</span> <span class="n">future1</span> <span class="o">=</span> <span class="n">promise1</span><span class="p">.</span><span class="n">get_future</span><span class="p">();</span> <span class="k">auto</span> <span class="n">waitFuture</span> <span class="o">=</span> <span class="n">future1</span><span class="p">.</span><span class="n">then</span><span class="p">([</span><span class="o">&amp;</span><span class="n">tmpValue</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">promise2</span><span class="p">](</span><span class="n">boost</span><span class="o">::</span><span class="n">future</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="n">future</span><span class="p">){</span> <span class="n">assert</span><span class="p">(</span><span class="n">future</span><span class="p">.</span><span class="n">is_ready</span><span class="p">());</span> <span class="c1">// this works correctly and is ready.</span> <span class="n">std</span><span class="o">::</span><span class="n">async</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">launch</span><span class="o">::</span><span class="n">async</span><span class="p">,</span> <span class="p">[</span><span class="o">&amp;</span><span class="n">promise2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">tmpValue</span><span class="p">](){</span> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep_for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">chrono</span><span class="o">::</span><span class="n">seconds</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span> <span class="n">tmpValue</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">promise2</span><span class="p">.</span><span class="n">set_value</span><span class="p">();</span> <span class="p">});</span> <span class="k">return</span> <span class="n">promise2</span><span class="p">.</span><span class="n">get_future</span><span class="p">();</span> <span class="p">}).</span><span class="n">then</span><span class="p">([</span><span class="o">&amp;</span><span class="n">value</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">tmpValue</span><span class="p">](</span><span class="n">boost</span><span class="o">::</span><span class="n">future</span><span class="o">&lt;</span><span class="kt">void</span><span class="o">&gt;</span> <span class="n">future</span><span class="p">){</span> <span class="c1">// this lambda is being called before the future is ready.</span> <span class="n">assert</span><span class="p">(</span><span class="n">future</span><span class="p">.</span><span class="n">is_ready</span><span class="p">());</span> <span class="c1">// this doesn&#39;t work correctly and is not ready.</span> <span class="c1">// if we call future.get() this will block until the promise2 has been set be I don&#39;t want</span> <span class="c1">// the then lambda to block. I want the lambda called when the future is ready.</span> <span class="n">value</span> <span class="o">=</span> <span class="n">tmpValue</span><span class="p">;</span> <span class="p">});</span> <span class="n">promise1</span><span class="p">.</span><span class="n">set_value</span><span class="p">();</span> <span class="n">waitFuture</span><span class="p">.</span><span class="n">wait</span><span class="p">();</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;value = &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">value</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="c1">// should print 1 but prints 0</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div></div> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12293 Trac 1.4.3 anonymous Thu, 23 Jun 2016 16:43:50 GMT summary changed https://svn.boost.org/trac10/ticket/12293#comment:1 https://svn.boost.org/trac10/ticket/12293#comment:1 <ul> <li><strong>summary</strong> <span class="trac-field-old">in boost 1.60.0 boost::future::then lambda called before future is ready.</span> → <span class="trac-field-new">boost::future::then lambda called before future is ready.</span> </li> </ul> Ticket viboes Mon, 08 Aug 2016 23:03:32 GMT owner, status changed https://svn.boost.org/trac10/ticket/12293#comment:2 https://svn.boost.org/trac10/ticket/12293#comment:2 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">viboes</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> Ticket viboes Mon, 08 Aug 2016 23:31:44 GMT <link>https://svn.boost.org/trac10/ticket/12293#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:3</guid> <description> <p> Hi, The following shouldn't compile </p> <pre class="wiki"> auto waitFuture = future1.then([&amp;tmpValue, &amp;promise2](boost::future&lt;void&gt; future){ assert(future.is_ready()); // this works correctly and is ready. </pre><p> Do you mean something else instead of future.is_ready? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 08 Aug 2016 23:32:57 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:4</guid> <description> <p> You should store the returned future otherwise it will block in </p> <pre class="wiki"> std::async(std::launch::async, [&amp;promise2, &amp;tmpValue](){ std::this_thread::sleep_for(std::chrono::seconds(1)); tmpValue = 1; promise2.set_value(); }); </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 08 Aug 2016 23:41:46 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:5</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12293#comment:3" title="Comment 3">viboes</a>: </p> <blockquote class="citation"> <p> Hi, The following shouldn't compile </p> <pre class="wiki"> auto waitFuture = future1.then([&amp;tmpValue, &amp;promise2](boost::future&lt;void&gt; future){ assert(future.is_ready()); // this works correctly and is ready. </pre><p> Do you mean something else instead of future.is_ready? </p> </blockquote> <p> Forget this I didn't saw the future parameter. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 08 Aug 2016 23:42:41 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:6</guid> <description> <p> Have you uncommented </p> <pre class="wiki">//#define BOOST_THREAD_VERSION 4 </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Tue, 09 Aug 2016 00:06:11 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:7</guid> <description> <p> I believe the problem is due to the fact that the continuation returns a future&lt;void&gt;. You will need to unwrap the returned future&lt;future&lt;void&gt;&gt; </p> <pre class="wiki"> }).unwrap().then([&amp;value, &amp;tmpValue](boost::future&lt;void&gt; future){ </pre><p> However, I would like that your code doesn't compile as the continuation should had a boost::future&lt;future&lt;void&gt;&gt; parameter. </p> <p> When I change the continuation as follows I get the expected error. </p> <pre class="wiki"> }).then([&amp;value, &amp;tmpValue](boost::future&lt;void&gt;&amp; future){ </pre><p> Note that the future is passed by reference. </p> <p> This mean that the call to the continuation is getting the embedded future. I will check this. </p> </description> <category>Ticket</category> </item> <item> <author>Jeffrey.Gramowski@…</author> <pubDate>Wed, 10 Aug 2016 15:52:18 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:8</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12293#comment:6" title="Comment 6">viboes</a>: </p> <blockquote class="citation"> <p> Have you uncommented </p> <pre class="wiki">//#define BOOST_THREAD_VERSION 4 </pre></blockquote> <p> Yes this is has been set in the header files for my boost version. I just wanted to document that it is set. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 15 Aug 2016 17:21:39 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:9</guid> <description> <p> Have you seen my comment 7? </p> </description> <category>Ticket</category> </item> <item> <author>Jeffrey.Gramowski@…</author> <pubDate>Mon, 15 Aug 2016 18:00:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:10</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12293#comment:9" title="Comment 9">viboes</a>: </p> <blockquote class="citation"> <p> Have you seen my comment 7? </p> </blockquote> <p> I tried the unwrap function and it works. But I still think that there is a problem. So either my code shouldn't compile and force the developer to use the unwrap function. Or if boost is going to do the "auto" unwrap functionality than it needs to do it in a way so that it is equivalent to calling the unwrap function. </p> <p> For now I guess I will call the unwrap function but I still think that something needs to be done here. The current implementation can introduce very hard to find bugs in a system dealing with threads. This is how I ran into this problem. I was trying to track down a deadlock in some multi-threaded code which wasn't suppose to block and I tracked it down to this condition. Note I am also using the executor functionality so that I can control the threads and our threads are not allowed to block. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 19 Aug 2016 21:40:36 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12293#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12293#comment:11</guid> <description> <p> I agree that there is a problem. But is is not that the unwrap must be done implicitly. </p> <p> Boost::future::then was defined before the C++ experimental std::experimental::future::then included in the TS and the original proposal behaved like Boost.Thread. Changing this will be a breaking change and people don't like that. </p> <p> The problem is that the future&lt;future&lt;void&gt;&gt; is implicitly convertible to future&lt;void&gt;, which must be explicit. I will see what happens if I define the constructor explicit. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 03 Sep 2016 11:55:49 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/12293#comment:12 https://svn.boost.org/trac10/ticket/12293#comment:12 <ul> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.62.0</span> </li> </ul> <p> <a class="ext-link" href="https://github.com/boostorg/thread/commit/fc748dbddf33baf2afd1cf33920a6c0da8511f77"><span class="icon">​</span>https://github.com/boostorg/thread/commit/fc748dbddf33baf2afd1cf33920a6c0da8511f77</a> </p> Ticket viboes Sat, 03 Sep 2016 11:57:07 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/12293#comment:13 https://svn.boost.org/trac10/ticket/12293#comment:13 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> <a class="ext-link" href="https://github.com/boostorg/thread/commit/58c6b384cc80ae2af598ab48d16522e71b31ca09"><span class="icon">​</span>https://github.com/boostorg/thread/commit/58c6b384cc80ae2af598ab48d16522e71b31ca09</a> </p> Ticket