Boost C++ Libraries: Ticket #11256: future<>::is_ready() == false in continuation function https://svn.boost.org/trac10/ticket/11256 <p> I have a few layers of future continuations that do some work on my future in order to finally pass it to the client. </p> <p> Today, I've coded the following to one of the layers (non-relevant parts edited out for brevity): </p> <div class="wiki-code"><div class="code"><pre> <span class="k">auto</span> <span class="n">promise</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">make_shared</span><span class="o">&lt;</span><span class="n">boost</span><span class="o">::</span><span class="n">promise</span><span class="o">&lt;</span><span class="n">ServerMessagePtr</span><span class="o">&gt;&gt;</span><span class="p">();</span> <span class="c1">// insert the promise into a container, where it will be fulfilled</span> <span class="c1">// if we receive a network reply</span> <span class="n">m_promises</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">acc</span><span class="p">,</span> <span class="n">messageId</span><span class="p">);</span> <span class="k">auto</span> <span class="n">sendFuture</span> <span class="o">=</span> <span class="n">LowerLayer</span><span class="o">::</span><span class="n">send</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">message</span><span class="p">),</span> <span class="n">retries</span><span class="p">);</span> <span class="k">auto</span> <span class="n">future</span> <span class="o">=</span> <span class="n">sendFuture</span><span class="p">.</span><span class="n">then</span><span class="p">(</span><span class="n">LowerLayer</span><span class="o">::</span><span class="n">m_ioServiceExecutor</span><span class="p">,</span> <span class="p">[</span><span class="k">this</span><span class="p">,</span> <span class="n">promise</span><span class="p">,</span> <span class="n">messageId</span><span class="p">](</span><span class="k">auto</span> <span class="n">f</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="n">has_exception</span><span class="p">())</span> <span class="p">{</span> <span class="k">this</span><span class="o">-&gt;</span><span class="n">m_promises</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">messageId</span><span class="p">);</span> <span class="n">f</span><span class="p">.</span><span class="n">get</span><span class="p">();</span> <span class="p">}</span> <span class="k">return</span> <span class="n">promise</span><span class="o">-&gt;</span><span class="n">get_future</span><span class="p">();</span> <span class="p">});</span> <span class="k">return</span> <span class="n">future</span><span class="p">.</span><span class="n">unwrap</span><span class="p">();</span> </pre></div></div><p> Previously, the layer simply returned <code>promise-&gt;get_future();</code> and everything was well. Currently, the code causes my final continuation to deadlock when using a single-threaded executor (as is the case in my unit tests). I've added an assertion where the thread locked: </p> <div class="wiki-code"><div class="code"><pre><span class="n">future</span><span class="p">.</span><span class="n">then</span><span class="p">(</span><span class="n">LowerLayer</span><span class="o">::</span><span class="n">m_ioServiceExecutor</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">f</span><span class="p">)</span> <span class="p">{</span> <span class="n">assert</span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="n">is_ready</span><span class="p">());</span> <span class="k">return</span> <span class="n">SvrMsg</span><span class="p">{</span><span class="n">f</span><span class="p">.</span><span class="n">get</span><span class="p">()};</span> <span class="p">}</span> </pre></div></div><p> Following is a trace from my unit tests: </p> <pre class="wiki">communicator_test: ../object/../src/communication/layers/translator.h:108: one::communication::layers::Translator&lt;LowerLayer&gt;::communicate(const one::messages::ClientMessage&amp;, int)::&lt;lambda(auto:7)&gt; [with auto:7 = boost::future&lt;std::unique_ptr&lt;one::clproto::ServerMessage&gt; &gt;; SvrMsg = one::messages::Pong; LowerLayer = one::communication::layers::Replier&lt;one::communication::layers::Inbox&lt;one::communication::layers::Sequencer&lt;one::communication::layers::BinaryTranslator&lt;one::communication::layers::Retrier&lt;LazyConnectionPool&gt; &gt; &gt; &gt; &gt;]: Assertion `f.is_ready()' failed. [Thread 0x7ffff4627700 (LWP 21) exited] Program received signal SIGABRT, Aborted. [Switching to Thread 0x7ffff5265700 (LWP 20)] 0x00007ffff5bd7e37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt #0 0x00007ffff5bd7e37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 #1 0x00007ffff5bd9528 in __GI_abort () at abort.c:89 #2 0x00007ffff5bd0ce6 in __assert_fail_base (fmt=0x7ffff5d20c08 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x574473 "f.is_ready()", file=file@entry=0x574440 "../object/../src/communication/layers/translator.h", line=line@entry=108, function=function@entry=0x57b540 &lt;_ZZZN3one13communication6layers10TranslatorINS1_7ReplierINS1_5InboxINS1_9SequencerINS1_16BinaryTranslatorINS1_7RetrierI18LazyConnectionPoolEEEEEEEEEEE11communicateINS_8messages4PongEEEDaRKNSG_13ClientMessageEiENKUlT_E_clIN5boost6futureISt10unique_ptrINS_7clproto13ServerMessageESt14default_deleteISS_EEEEEEDaT_E19__PRETTY_FUNCTION__&gt; "one::communication::layers::Translator&lt;LowerLayer&gt;::communicate(const one::messages::ClientMessage&amp;, int)::&lt;lambda(auto:7)&gt; [with auto:7 = boost::future&lt;std::unique_ptr&lt;one::clproto::ServerMessage&gt; &gt;;"...) at assert.c:92 #3 0x00007ffff5bd0d92 in __GI___assert_fail (assertion=0x574473 "f.is_ready()", file=0x574440 "../object/../src/communication/layers/translator.h", line=108, function=0x57b540 &lt;_ZZZN3one13communication6layers10TranslatorINS1_7ReplierINS1_5InboxINS1_9SequencerINS1_16BinaryTranslatorINS1_7RetrierI18LazyConnectionPoolEEEEEEEEEEE11communicateINS_8messages4PongEEEDaRKNSG_13ClientMessageEiENKUlT_E_clIN5boost6futureISt10unique_ptrINS_7clproto13ServerMessageESt14default_deleteISS_EEEEEEDaT_E19__PRETTY_FUNCTION__&gt; "one::communication::layers::Translator&lt;LowerLayer&gt;::communicate(const one::messages::ClientMessage&amp;, int)::&lt;lambda(auto:7)&gt; [with auto:7 = boost::future&lt;std::unique_ptr&lt;one::clproto::ServerMessage&gt; &gt;;"...) at assert.c:101 #4 0x00000000005014bf in _ZZN3one13communication6layers10TranslatorINS1_7ReplierINS1_5InboxINS1_9SequencerINS1_16BinaryTranslatorINS1_7RetrierI18LazyConnectionPoolEEEEEEEEEEE11communicateINS_8messages4PongEEEDaRKNSG_13ClientMessageEiENKUlT_E_clIN5boost6futureISt10unique_ptrINS_7clproto13ServerMessageESt14default_deleteISS_EEEEEEDaT_ (__closure=0x7ef090, f=...) at ../object/../src/communication/layers/translator.h:108 #5 0x0000000000530a90 in _ZN5boost6detail41future_executor_continuation_shared_stateINS_9executors17basic_thread_poolENS_6futureISt10unique_ptrIN3one7clproto13ServerMessageESt14default_deleteIS8_EEEENS6_8messages4PongEZNS6_13communication6layers10TranslatorINSG_7ReplierINSG_5InboxINSG_9SequencerINSG_16BinaryTranslatorINSG_7RetrierI18LazyConnectionPoolEEEEEEEEEEE11communicateISE_EEDaRKNSD_13ClientMessageEiEUlT_E_E3runENS_10shared_ptrINS0_17shared_state_baseEEE ( that_=...) at /usr/include/boost/thread/future.hpp:4281 #6 0x00000000005307b2 in _ZN5boost6detail6run_itINS0_41future_executor_continuation_shared_stateINS_9executors17basic_thread_poolENS_6futureISt10unique_ptrIN3one7clproto13ServerMessageESt14default_deleteIS9_EEEENS7_8messages4PongEZNS7_13communication6layers10TranslatorINSH_7ReplierINSH_5InboxINSH_9SequencerINSH_16BinaryTranslatorINSH_7RetrierI18LazyConnectionPoolEEEEEEEEEEE11communicateISF_EEDaRKNSE_13ClientMessageEiEUlT_E_EEEclEv (this=0x7fffec000a88) at /usr/include/boost/thread/future.hpp:4252 #7 0x0000000000530548 in _ZN5boost6detail16nullary_functionIFvvEE9impl_typeINS0_6run_itINS0_41future_executor_continuation_shared_stateINS_9executors17basic_thread_poolENS_6futureISt10unique_ptrIN3one7clproto13ServerMessageESt14default_deleteISD_EEEENSB_8messages4PongEZNSB_13communication6layers10TranslatorINSL_7ReplierINSL_5InboxINSL_9SequencerINSL_16BinaryTranslatorINSL_7RetrierI18LazyConnectionPoolEEEEEEEEEEE11communicateISJ_EEDaRKNSI_13ClientMessageEiEUlT_E_EEEEE4callEv (this=0x7fffec000a80) at /usr/include/boost/thread/detail/nullary_function.hpp:52 #8 0x00000000004fa3fd in boost::detail::nullary_function&lt;void ()&gt;::operator()() (this=0x7ffff5264dd0) at /usr/include/boost/thread/detail/nullary_function.hpp:125 #9 0x0000000000500325 in boost::executors::basic_thread_pool::worker_thread (this=0x7edb10) at /usr/include/boost/thread/executors/basic_thread_pool.hpp:92 #10 0x000000000052e55b in boost::detail::invoke&lt;void (boost::executors::basic_thread_pool::*)(), boost::executors::basic_thread_pool&lt;&gt;*&gt;(void (boost::executors::basic_thread_pool::*&amp;&amp;)(), boost::executors::basic_thread_pool&lt;&gt;*&amp;&amp;, (boost::executors::basic_thread_pool&lt;&gt;*&amp;&amp;)...) (f=&lt;unknown type in /home/kzemek/plgrid/helpers/debug/test/unit/communicator_test, CU 0xa555, DIE 0xa1c35&gt;, a0=&lt;unknown type in /home/kzemek/plgrid/helpers/debug/test/unit/communicator_test, CU 0xa555, DIE 0xa1c3a&gt;) at /usr/include/boost/thread/detail/invoke.hpp:77 #11 0x000000000052c5fd in boost::detail::thread_data&lt;void (boost::executors::basic_thread_pool::*)(), boost::executors::basic_thread_pool*&gt;::run2&lt;1ul&gt; (this=0x7ec1d0) at /usr/include/boost/thread/detail/thread.hpp:75 #12 0x0000000000529c02 in boost::detail::thread_data&lt;void (boost::executors::basic_thread_pool::*)(), boost::executors::basic_thread_pool*&gt;::run (this=0x7ec1d0) at /usr/include/boost/thread/detail/thread.hpp:81 #13 0x00007ffff766fd8a in ?? () from /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.58.0 #14 0x00007ffff72450a5 in start_thread (arg=0x7ffff5265700) at pthread_create.c:309 #15 0x00007ffff5c9acfd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111 </pre><p> I haven't yet found an exact reason for the failure. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/11256 Trac 1.4.3 viboes Fri, 01 May 2015 15:46:01 GMT owner, status changed https://svn.boost.org/trac10/ticket/11256#comment:1 https://svn.boost.org/trac10/ticket/11256#comment:1 <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> <p> I will take a look. </p> <p> A public example able to reproduce the issue will be welcome. </p> <p> Please, could you tell me which version are you using? develop, master or the released boost1.58? </p> <p> Which compiler and platform? </p> Ticket Konrad Zemek <konrad.zemek@…> Fri, 01 May 2015 22:24:34 GMT <link>https://svn.boost.org/trac10/ticket/11256#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:2</guid> <description> <p> I'll try to put together an example to reproduce; I had very limited time when the issue popped up, and I couldn't get a simple example to fail. </p> <p> I'll also try and trace calls in future.hpp to get an understanding of what logic leads to the continuation being triggered prematurely. </p> <p> I'm using released Boost 1.58 patched with fix for future&lt;&gt;::then with executors not compiling; the future.hpp is effectively the one from commit 0bed674 . I'm using 64-bit Ubuntu 14.10 with GCC 4.9.1 . </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 02 May 2015 08:59:06 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:3</guid> <description> <p> I've reached to reproduce it. </p> </description> <category>Ticket</category> </item> <item> <author>Konrad Zemek <konrad.zemek@…></author> <pubDate>Sat, 02 May 2015 19:10:29 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:4</guid> <description> <p> Below is the simplest code I got to reproduce if anyone else is curious. This version fails on assert, but when you remove <code>.unwrap()</code> it deadlocks instead (in this particular version, <code>boost::lock</code> throws exception saying "resource deadlock avoided", but my other code just deadlocks). </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#define BOOST_THREAD_VERSION 4</span> <span class="cp">#define BOOST_THREAD_PROVIDES_EXECUTORS</span> <span class="cp">#include</span> <span class="cpf">&lt;boost/thread.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;boost/thread/thread_pool.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;cassert&gt;</span><span class="cp"></span> <span class="k">auto</span> <span class="nf">createFuture</span><span class="p">()</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">promise</span><span class="p">;</span> <span class="n">promise</span><span class="p">.</span><span class="n">set_value</span><span class="p">();</span> <span class="k">return</span> <span class="n">promise</span><span class="p">.</span><span class="n">get_future</span><span class="p">();</span> <span class="p">}</span> <span class="k">auto</span> <span class="nf">stepOne</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">basic_thread_pool</span> <span class="o">&amp;</span><span class="n">executor</span><span class="p">)</span> <span class="p">{</span> <span class="k">auto</span> <span class="n">sendFuture</span> <span class="o">=</span> <span class="n">createFuture</span><span class="p">();</span> <span class="k">auto</span> <span class="n">wrappedFuture</span> <span class="o">=</span> <span class="n">sendFuture</span><span class="p">.</span><span class="n">then</span><span class="p">(</span><span class="n">executor</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">f</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span> <span class="k">return</span> <span class="n">createFuture</span><span class="p">();</span> <span class="p">});</span> <span class="k">return</span> <span class="n">wrappedFuture</span><span class="p">.</span><span class="n">unwrap</span><span class="p">();</span> <span class="p">}</span> <span class="k">auto</span> <span class="nf">stepTwo</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">basic_thread_pool</span> <span class="o">&amp;</span><span class="n">executor</span><span class="p">)</span> <span class="p">{</span> <span class="k">auto</span> <span class="n">future</span> <span class="o">=</span> <span class="n">stepOne</span><span class="p">(</span><span class="n">executor</span><span class="p">);</span> <span class="k">return</span> <span class="n">future</span><span class="p">.</span><span class="n">then</span><span class="p">(</span><span class="n">executor</span><span class="p">,</span> <span class="p">[](</span><span class="k">auto</span> <span class="n">f</span><span class="p">)</span> <span class="p">{</span> <span class="n">assert</span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="n">is_ready</span><span class="p">());</span> <span class="p">});</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="n">boost</span><span class="o">::</span><span class="n">basic_thread_pool</span> <span class="n">executor</span><span class="p">{</span><span class="mi">1</span><span class="p">};</span> <span class="n">stepTwo</span><span class="p">(</span><span class="n">executor</span><span class="p">).</span><span class="n">get</span><span class="p">();</span> <span class="p">}</span> </pre></div></div> </description> <category>Ticket</category> </item> <item> <author>Konrad Zemek <konrad.zemek@…></author> <pubDate>Sat, 02 May 2015 19:21:34 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:5</guid> <description> <p> Here's the trace for the <code>boost::lock</code> exception (Boost.Thread from commit e598796eaf, i.e. current develop): </p> <pre class="wiki">terminate called after throwing an instance of 'boost::exception_detail::clone_impl&lt;boost::exception_detail::error_info_injector&lt;boost::lock_error&gt; &gt;' what(): boost unique_lock owns already the mutex: Resource deadlock avoided Program received signal SIGABRT, Aborted. 0x00007ffff70ffe37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt #0 0x00007ffff70ffe37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 #1 0x00007ffff7101528 in __GI_abort () at abort.c:89 #2 0x00007ffff770505d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #3 0x00007ffff7702ed6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #4 0x00007ffff7702f21 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #5 0x00007ffff7703139 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #6 0x0000000000411f65 in boost::throw_exception&lt;boost::lock_error&gt; (e=...) at /usr/include/boost/throw_exception.hpp:69 #7 0x00000000004146e6 in boost::unique_lock&lt;boost::mutex&gt;::lock (this=0x7fffffffe480) at thread/include/boost/thread/lock_types.hpp:343 #8 0x000000000040adcb in boost::detail::make_future_executor_continuation_shared_state&lt;boost::executors::basic_thread_pool, boost::future&lt;boost::future&lt;void&gt; &gt;, void, stepTwo(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:2)&gt; &gt;(boost::executors::basic_thread_pool &amp;, boost::unique_lock&lt;boost::mutex&gt; &amp;, &lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3d241&gt;, &lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3d21b&gt;) (ex=..., lock=..., f=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3d241&gt;, c=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3d21b&gt;) at thread/include/boost/thread/future.hpp:4703 #9 0x000000000040aad0 in boost::future&lt;boost::future&lt;void&gt; &gt;::then&lt;boost::executors::basic_thread_pool, stepTwo(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:2)&gt; &gt;(boost::executors::basic_thread_pool &amp;, &lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x37065&gt;) (this=0x7fffffffe4e0, ex=..., func=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x37065&gt;) at thread/include/boost/thread/future.hpp:4874 #10 0x000000000040a872 in stepTwo (executor=...) at example.cpp:30 #11 0x000000000040a901 in main () at example.cpp:36 </pre> </description> <category>Ticket</category> </item> <item> <author>Konrad Zemek <konrad.zemek@…></author> <pubDate>Sat, 02 May 2015 19:53:02 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:6</guid> <description> <p> This simple change seems to fix the problems: <a class="ext-link" href="https://github.com/kzemek/thread/commit/f4c65a2f6ebb0f0edbf83272b6d8444101efb39e"><span class="icon">​</span>https://github.com/kzemek/thread/commit/f4c65a2f6ebb0f0edbf83272b6d8444101efb39e</a> </p> <p> This just introduces the same locking logic as with creating a non-nested future continuation (future.hpp:4803). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 12:35:05 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:7</guid> <description> <p> I've committed some changes concerning the missed lock.unlock (<a class="ext-link" href="https://github.com/boostorg/thread/commit/5205fa71bfc06a8eac22fc2a49357d1db1ef505f"><span class="icon">​</span>https://github.com/boostorg/thread/commit/5205fa71bfc06a8eac22fc2a49357d1db1ef505f</a>). </p> <p> I've added also your example, but this doesn't solves the is_ready issue. So I have created a new ticket <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/11263" title="#11263: Bugs: lock already locked lock (closed: fixed)">#11263</a>. </p> <p> IN the test_10964 there are yet some cases that doesn't work. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 14:48:56 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:8</guid> <description> <p> I'm not yet sure but I believe that I find where the bug is. A unwrapped future shouldn't is not a continuation so no need for the adding it self as a continuation at the construction time </p> <pre class="wiki"> template &lt;class F, class Rp&gt; BOOST_THREAD_FUTURE&lt;Rp&gt; make_future_unwrap_shared_state(boost::unique_lock&lt;boost::mutex&gt; &amp;lock, BOOST_THREAD_RV_REF(F) f) { shared_ptr&lt;future_unwrap_shared_state&lt;F, Rp&gt; &gt; h(new future_unwrap_shared_state&lt;F, Rp&gt;(boost::move(f))); // lock.lock(); // h-&gt;parent.future_-&gt;set_continuation_ptr(h, lock); // lock.unlock(); return BOOST_THREAD_FUTURE&lt;Rp&gt;(h); } </pre><p> In addition the name of the wrapped future was misleading (parent). The code </p> <pre class="wiki"> virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock&lt;boost::mutex&gt;&amp; lock) { boost::unique_lock&lt;boost::mutex&gt; lk(wrapped.parent.future_-&gt;mutex); parent.future_-&gt;set_continuation_ptr(continuation, lk); } </pre><p> was setting a continuation on the wrapped (and already ready future, not on the parent one). </p> <p> I've renamed the parent member to wrapped. The code should be </p> <pre class="wiki"> virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock&lt;boost::mutex&gt;&amp; lock) { boost::unique_lock&lt;boost::mutex&gt; lk(wrapped.parent.future_-&gt;mutex); wrapped.get().future_-&gt;set_continuation_ptr(continuation, lk); } </pre><p> Please, could you try with this change </p> <pre class="wiki"> template&lt;typename F, typename Rp&gt; struct future_unwrap_shared_state: shared_state&lt;Rp&gt; { F wrapped; public: explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) : wrapped(boost::move(f)) {} typename F::value_type parent_value(boost::unique_lock&lt;boost::mutex&gt;&amp; ) { typename F::value_type r = wrapped.get(); r.set_exceptional_if_invalid(); return boost::move(r); } virtual void wait(boost::unique_lock&lt;boost::mutex&gt;&amp; lk, bool ) { // todo see if rethrow must be used parent_value(lk).wait(); } virtual Rp get(boost::unique_lock&lt;boost::mutex&gt;&amp; lk) { return parent_value(lk).get(); } #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION typedef shared_ptr&lt;shared_state_base&gt; continuation_ptr_type; virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock&lt;boost::mutex&gt;&amp; lock) { boost::unique_lock&lt;boost::mutex&gt; lk(wrapped.parent.future_-&gt;mutex); wrapped.get().future_-&gt;set_continuation_ptr(continuation, lk); } #endif }; template &lt;class F, class Rp&gt; BOOST_THREAD_FUTURE&lt;Rp&gt; make_future_unwrap_shared_state(boost::unique_lock&lt;boost::mutex&gt; &amp;lock, BOOST_THREAD_RV_REF(F) f) { shared_ptr&lt;future_unwrap_shared_state&lt;F, Rp&gt; &gt; h(new future_unwrap_shared_state&lt;F, Rp&gt;(boost::move(f))); // lock.lock(); // h-&gt;parent.future_-&gt;set_continuation_ptr(h, lock); // lock.unlock(); return BOOST_THREAD_FUTURE&lt;Rp&gt;(h); } } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 15:21:59 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:9</guid> <description> <p> Sorry, the previous code don't work neither nor compile :( </p> </description> <category>Ticket</category> </item> <item> <author>Konrad Zemek <konrad.zemek@…></author> <pubDate>Sun, 03 May 2015 15:45:34 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:10</guid> <description> <p> I assumed it should be simply <code>wrapped.future_-&gt;mutex</code> and changed it as such to avoid compilation error. Using the modified code with the example I posted above results in a deadlock: </p> <pre class="wiki">Thread 2 (Thread 0x7ffff699c700 (LWP 172)): #0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135 #1 0x00007ffff6cad56a in _L_lock_913 () from /lib/x86_64-linux-gnu/libpthread.so.0 #2 0x00007ffff6cad390 in __GI___pthread_mutex_lock (mutex=0x64a6b0) at ../nptl/pthread_mutex_lock.c:79 #3 0x000000000040de34 in pthread_mutex_lock (m=0x64a6b0) at thread/include/boost/thread/pthread/mutex.hpp:62 #4 boost::mutex::lock (this=0x64a6b0) at thread/include/boost/thread/pthread/mutex.hpp:116 #5 0x0000000000414a01 in boost::unique_lock&lt;boost::mutex&gt;::lock (this=0x7ffff699bc60) at thread/include/boost/thread/lock_types.hpp:346 #6 0x00000000004128ed in boost::unique_lock&lt;boost::mutex&gt;::unique_lock (this=0x7ffff699bc60, m_=...) at thread/include/boost/thread/lock_types.hpp:124 #7 0x000000000042b983 in boost::detail::shared_state&lt;boost::future&lt;void&gt; &gt;::mark_finished_with_result(boost::future&lt;void&gt;&amp;&amp;) (this=0x64a670, result_=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x1b312&gt;) at thread/include/boost/thread/future.hpp:551 #8 0x000000000040c9c3 in boost::detail::future_executor_continuation_shared_state&lt;boost::executors::basic_thread_pool, boost::future&lt;void&gt;, boost::future&lt;void&gt;, stepOne(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:1)&gt; &gt;::run(boost::shared_ptr&lt;boost::detail::shared_state_base&gt;) (that_=...) at thread/include/boost/thread/future.hpp:4303 #9 0x000000000040c82a in boost::detail::run_it&lt;boost::detail::future_executor_continuation_shared_state&lt;boost::executors::basic_thread_pool, boost::future&lt;void&gt;, boost::future&lt;void&gt;, stepOne(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:1)&gt; &gt; &gt;::operator()(void) (this=0x64a838) at thread/include/boost/thread/future.hpp:4274 #10 0x000000000040c79c in boost::detail::nullary_function&lt;void()&gt;::impl_type&lt;boost::detail::run_it&lt;boost::detail::future_executor_continuation_shared_state&lt;boost::executors::basic_thread_pool, boost::future&lt;void&gt;, boost::future&lt;void&gt;, stepOne(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:1)&gt; &gt; &gt; &gt;::call(void) (this=0x64a830) at thread/include/boost/thread/detail/nullary_function.hpp:52 #11 0x000000000040ec67 in boost::detail::nullary_function&lt;void ()&gt;::operator()() (this=0x7ffff699bdd0) at thread/include/boost/thread/detail/nullary_function.hpp:125 #12 0x00000000004119ed in boost::executors::basic_thread_pool::worker_thread (this=0x7fffffffe530) at thread/include/boost/thread/executors/basic_thread_pool.hpp:91 #13 0x000000000042ada9 in boost::detail::invoke&lt;void (boost::executors::basic_thread_pool::*)(), boost::executors::basic_thread_pool&lt;&gt;*&gt;(void (boost::executors::basic_thread_pool::*&amp;&amp;)(), boost::executors::basic_thread_pool&lt;&gt;*&amp;&amp;, (boost::executors::basic_thread_pool&lt;&gt;*&amp;&amp;)...) (f=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x4cba2&gt;, a0=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x4cba7&gt;) at thread/include/boost/thread/detail/invoke.hpp:77 #14 0x0000000000429815 in boost::detail::thread_data&lt;void (boost::executors::basic_thread_pool::*)(), boost::executors::basic_thread_pool*&gt;::run2&lt;1ul&gt; (this=0x64a0f0) at thread/include/boost/thread/detail/thread.hpp:75 #15 0x00000000004278c6 in boost::detail::thread_data&lt;void (boost::executors::basic_thread_pool::*)(), boost::executors::basic_thread_pool*&gt;::run (this=0x64a0f0) at thread/include/boost/thread/detail/thread.hpp:81 #16 0x00007ffff7bc7d8a in ?? () from /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.58.0 #17 0x00007ffff6cab0a5 in start_thread (arg=0x7ffff699c700) at pthread_create.c:309 #18 0x00007ffff71c2cfd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111 Thread 1 (Thread 0x7ffff7fe6780 (LWP 168)): #0 __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135 #1 0x00007ffff6cad56a in _L_lock_913 () from /lib/x86_64-linux-gnu/libpthread.so.0 #2 0x00007ffff6cad390 in __GI___pthread_mutex_lock (mutex=0x64a6b0) at ../nptl/pthread_mutex_lock.c:79 #3 0x000000000040de34 in pthread_mutex_lock (m=0x64a6b0) at thread/include/boost/thread/pthread/mutex.hpp:62 #4 boost::mutex::lock (this=0x64a6b0) at thread/include/boost/thread/pthread/mutex.hpp:116 #5 0x0000000000414a01 in boost::unique_lock&lt;boost::mutex&gt;::lock (this=0x7fffffffe2e0) at thread/include/boost/thread/lock_types.hpp:346 #6 0x00000000004128ed in boost::unique_lock&lt;boost::mutex&gt;::unique_lock (this=0x7fffffffe2e0, m_=...) at thread/include/boost/thread/lock_types.hpp:124 #7 0x000000000042993c in boost::future&lt;boost::future&lt;void&gt; &gt;::get (this=0x64a998) at thread/include/boost/thread/future.hpp:1868 #8 0x0000000000427ac9 in boost::detail::future_unwrap_shared_state&lt;boost::future&lt;boost::future&lt;void&gt; &gt;, void&gt;::set_continuation_ptr (this=0x64a890, continuation=..., lock=...) at thread/include/boost/thread/future.hpp:5068 #9 0x000000000040ae5c in boost::detail::make_future_executor_continuation_shared_state&lt;boost::executors::basic_thread_pool, boost::future&lt;void&gt;, void, stepTwo(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:2)&gt; &gt;(boost::executors::basic_thread_pool &amp;, boost::unique_lock&lt;boost::mutex&gt; &amp;, &lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3dc9c&gt;, &lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3dc76&gt;) (ex=..., lock=..., f=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3dc9c&gt;, c=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x3dc76&gt;) at thread/include/boost/thread/future.hpp:4704 #10 0x000000000040ab0c in boost::future&lt;void&gt;::then&lt;boost::executors::basic_thread_pool, stepTwo(boost::executors::basic_thread_pool&amp;)::&lt;lambda(auto:2)&gt; &gt;(boost::executors::basic_thread_pool &amp;, &lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x379fd&gt;) (this=0x7fffffffe4e0, ex=..., func=&lt;unknown type in /home/kzemek/plgrid/helpers/example, CU 0x0, DIE 0x379fd&gt;) at thread/include/boost/thread/future.hpp:4804 #11 0x000000000040a8a2 in stepTwo (executor=...) at example.cpp:30 #12 0x000000000040a931 in main () at example.cpp:36 </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 18:49:42 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:11</guid> <description> <p> The following design seems to work well except for the example future_unwrap.cpp. </p> <p> The unwrap shared state adds a continuation on the wrapped shared state. There is no redefinition for wait or get neither the set_continuation_ptr. Please could you try it? </p> <pre class="wiki"> template&lt;typename F, typename Rp&gt; struct future_unwrap_shared_state: shared_state&lt;Rp&gt; { F wrapped; typename F::value_type unwrapped; public: explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) : wrapped(boost::move(f)) { } void launch_continuation(boost::unique_lock&lt;boost::mutex&gt;&amp; lk, shared_ptr&lt;shared_state_base&gt; that) { if (! unwrapped.valid() ) { unwrapped = wrapped.get(); if (unwrapped.valid()) { boost::unique_lock&lt;boost::mutex&gt; lk2(unwrapped.future_-&gt;mutex); unwrapped.future_-&gt;set_continuation_ptr(this-&gt;shared_from_this(), lk2); } else { this-&gt;mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); } } else { this-&gt;mark_finished_with_result_internal(unwrapped.get(), lk); } } }; template&lt;typename F&gt; struct future_unwrap_shared_state&lt;F,void&gt;: shared_state&lt;void&gt; { F wrapped; typename F::value_type unwrapped; public: explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) : wrapped(boost::move(f)) { } void launch_continuation(boost::unique_lock&lt;boost::mutex&gt;&amp; lk, shared_ptr&lt;shared_state_base&gt; that) { if (! unwrapped.valid() ) { unwrapped = wrapped.get(); if (unwrapped.valid()) { lk.unlock(); boost::unique_lock&lt;boost::mutex&gt; lk2(unwrapped.future_-&gt;mutex); unwrapped.future_-&gt;set_continuation_ptr(this-&gt;shared_from_this(), lk2); } else { this-&gt;mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); } } else { unwrapped.wait(); this-&gt;mark_finished_with_result_internal(lk); } } }; template &lt;class F, class Rp&gt; BOOST_THREAD_FUTURE&lt;Rp&gt; make_future_unwrap_shared_state(boost::unique_lock&lt;boost::mutex&gt; &amp;lock, BOOST_THREAD_RV_REF(F) f) { shared_ptr&lt;future_unwrap_shared_state&lt;F, Rp&gt; &gt; h(new future_unwrap_shared_state&lt;F, Rp&gt;(boost::move(f))); lock.lock(); h-&gt;wrapped.future_-&gt;set_continuation_ptr(h, lock); lock.unlock(); return BOOST_THREAD_FUTURE&lt;Rp&gt;(h); } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 18:59:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:12</guid> <description> <p> Found. A missing unlock here </p> <pre class="wiki"> template&lt;typename F, typename Rp&gt; struct future_unwrap_shared_state: shared_state&lt;Rp&gt; { F wrapped; typename F::value_type unwrapped; public: explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) : wrapped(boost::move(f)) { } void launch_continuation(boost::unique_lock&lt;boost::mutex&gt;&amp; lk, shared_ptr&lt;shared_state_base&gt; that) { if (! unwrapped.valid() ) { unwrapped = wrapped.get(); if (unwrapped.valid()) { </pre> </description> <category>Ticket</category> </item> <item> <author>Konrad Zemek <konrad.zemek@…></author> <pubDate>Sun, 03 May 2015 20:22:29 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:13</guid> <description> <p> This does seem to fix <code>assert(f.is_ready())</code> problem, but <code>unwrapped = wrapped.get();</code> throws if <code>wrapped</code> has been fulfilled with an exception. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 20:34:08 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:14 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:14</guid> <description> <p> This is normal. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 20:34:15 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:15 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:15</guid> <description> <p> <a class="ext-link" href="https://github.com/boostorg/thread/commit/b7b2a463cfebdaeb697fbb667858c5fd35998f14"><span class="icon">​</span>https://github.com/boostorg/thread/commit/b7b2a463cfebdaeb697fbb667858c5fd35998f14</a> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 20:36:11 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:16 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:16</guid> <description> <p> Oh, I see what you mean. In the implementation I need to take care of this exception. And propagate it. I will do it. </p> </description> <category>Ticket</category> </item> <item> <author>Konrad Zemek <konrad.zemek@…></author> <pubDate>Sun, 03 May 2015 20:39:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:17 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:17</guid> <description> <p> Yeah, sorry for not being clearer. :) </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 20:53:26 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:18 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:18</guid> <description> <p> Not tested yet </p> <pre class="wiki"> template&lt;typename F, typename Rp&gt; struct future_unwrap_shared_state: shared_state&lt;Rp&gt; { F wrapped; typename F::value_type unwrapped; public: explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) : wrapped(boost::move(f)) { } void launch_continuation(boost::unique_lock&lt;boost::mutex&gt;&amp; lk, shared_ptr&lt;shared_state_base&gt; that) { if (! unwrapped.valid() ) { if (wrapped.has_exception()) { this-&gt;mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); } else { unwrapped = wrapped.get(); if (unwrapped.valid()) { lk.unlock(); boost::unique_lock&lt;boost::mutex&gt; lk2(unwrapped.future_-&gt;mutex); unwrapped.future_-&gt;set_continuation_ptr(this-&gt;shared_from_this(), lk2); } else { this-&gt;mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); } } } else { if (unwrapped.has_exception()) { this-&gt;mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); } else { this-&gt;mark_finished_with_result_internal(unwrapped.get(), lk); } } } }; </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 20:54:14 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11256#comment:19 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:19</guid> <description> <p> <a class="ext-link" href="https://github.com/boostorg/thread/commit/71d9a0a12010583a59548dc32bb1cb84f16a5d56"><span class="icon">​</span>https://github.com/boostorg/thread/commit/71d9a0a12010583a59548dc32bb1cb84f16a5d56</a> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 03 May 2015 20:55:34 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/11256#comment:20 https://svn.boost.org/trac10/ticket/11256#comment:20 <ul> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.59.0</span> </li> </ul> Ticket Konrad Zemek <konrad.zemek@…> Sun, 03 May 2015 21:19:34 GMT <link>https://svn.boost.org/trac10/ticket/11256#comment:21 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11256#comment:21</guid> <description> <p> It does work in my tests. Thanks for the great work! :) </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Thu, 13 Aug 2015 06:59:18 GMT</pubDate> <title>milestone changed https://svn.boost.org/trac10/ticket/11256#comment:22 https://svn.boost.org/trac10/ticket/11256#comment:22 <ul> <li><strong>milestone</strong> <span class="trac-field-old">Boost 1.59.0</span> → <span class="trac-field-new">Boost 1.60.0</span> </li> </ul> Ticket viboes Wed, 02 Sep 2015 18:10:16 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/11256#comment:23 https://svn.boost.org/trac10/ticket/11256#comment:23 <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/a3497e1ffceb14318ff09e339a53293926351057"><span class="icon">​</span>https://github.com/boostorg/thread/commit/a3497e1ffceb14318ff09e339a53293926351057</a> </p> Ticket