Boost C++ Libraries: Ticket #4531: [Thread] ::promise shared between threads race-condition https://svn.boost.org/trac10/ticket/4531 <p> I believe I have discovered a problem with boost::promise when it's shared via threads. I described the problem (informally) on the <a class="ext-link" href="http://lists.boost.org/boost-users/2010/08/61530.php"><span class="icon">​</span>boost-users-list</a>. </p> <p> As suggested by Anthony Williams I raise a ticket for this bug here. Another anonymous helper also suggested that I create a standalone test-case for my bug, which I have done as well. You can find it attached. </p> <p> The test case can be made like this: </p> <pre class="wiki">g++ -O0 -g -static -I /usr/local/boost_1_43_0 boostpromise.cpp -o boostpromise -L/usr/local/boost_1_43_0/stage/lib/ -lboost_thread -lpthread </pre><p> run like this: ./boostpromise </p> <p> it will do an (endless) loop and usually results in an error (but no crash) or a core-dump (about 50-50 it seems). Either happens usually before several hundred iterations. Expected output is: </p> <pre class="wiki">... [11805] ok : 11815 [11806] ok : 11816 [11807] ok : 11817 [11808] ok : 11818 [11809] ok : 11819 [11810] ok : 11820 [11811] ok : 11821 ... </pre><p> When I change the boost file /usr/local/boost_1_43_0/boost/thread/future.hpp and add lazy_init(); in the promise constructor (around line 919), the boostpromise program runs for a million iterations without problems. I guess this is not the best solution, because it's not lazy anymore, but solves my problem for now. </p> <pre class="wiki">promise(): future(),future_obtained(false) { lazy_init(); } </pre><p> back trace from coredump below: </p> <pre class="wiki">(gdb) bt #0 0xffffe410 in __kernel_vsyscall () #1 0x08105f78 in raise () #2 0x080d81b2 in abort () #3 0x080d3c3d in __assert_fail () #4 0x08060a4f in ~mutex (this=0x8174330) at /usr/local/boost_1_43_0/boost/thread/pthread/mutex.hpp:46 #5 0x08060ab7 in ~future_object_base (this=0x8174320) at /usr/local/boost_1_43_0/boost/thread/future.hpp:104 #6 0x08060b87 in ~future_object (this=0x8174320) at /usr/local/boost_1_43_0/boost/thread/future.hpp:290 #7 0x0804cc6c in boost::checked_delete&lt;boost::detail::future_object&lt;Packet&gt; &gt; (x=0x8174320) at /usr/local/boost_1_43_0/boost/checked_delete.hpp:34 #8 0x0804dd04 in boost::detail::sp_counted_impl_p&lt;boost::detail::future_object&lt;Packet&gt; &gt;::dispose (this=0x81742d8) at /usr/local/boost_1_43_0/boost/smart_ptr/detail/sp_counted_impl.hpp:78 #9 0x08048894 in boost::detail::sp_counted_base::release (this=0x81742d8) at /usr/local/boost_1_43_0/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:145 #10 0x080488da in ~shared_count (this=0xbf8d7fc4) at /usr/local/boost_1_43_0/boost/smart_ptr/detail/shared_count.hpp:217 #11 0x080492d2 in ~shared_ptr (this=0xbf8d7fc0) at /usr/local/boost_1_43_0/boost/smart_ptr/shared_ptr.hpp:169 #12 0x08051aa5 in boost::shared_ptr&lt;boost::detail::future_object&lt;Packet&gt; &gt;::reset&lt;boost::detail::future_object&lt;Packet&gt; &gt; (this=0x8171f68, p=0x8174260) at /usr/local/boost_1_43_0/boost/smart_ptr/shared_ptr.hpp:392 #13 0x08061397 in boost::promise&lt;Packet&gt;::lazy_init (this=0x8171f68) at /usr/local/boost_1_43_0/boost/thread/future.hpp:909 #14 0x080616e8 in boost::promise&lt;Packet&gt;::get_future (this=0x8171f68) at /usr/local/boost_1_43_0/boost/thread/future.hpp:978 #15 0x08048425 in main () at boostpromise.cpp:70 (gdb) </pre><p> ps, attaching the test file gave a TRAC error ( </p> <pre class="wiki">OperationalError: database is locked </pre><p> so I just inline it here, boospromise.cpp : </p> <pre class="wiki">#include &lt;boost/thread.hpp&gt; class Packet { public: Packet(int i) : in(i) {} int in; }; typedef boost::promise&lt; Packet &gt; packet_promise; typedef boost::shared_ptr&lt; packet_promise &gt; packet_promise_shared_ptr; typedef std::pair&lt; unsigned long, packet_promise_shared_ptr &gt; seq_promise_pair; typedef std::map&lt; unsigned long, packet_promise_shared_ptr &gt; seq_to_promise_map; class Demo { private: boost::thread setvalue_thread_; seq_to_promise_map mymap_; boost::mutex mymap_mutex_; unsigned long counter_; public: Demo() : counter_(10), setvalue_thread_(boost::bind(&amp;Demo::do_calc_in_thread, this)) { } packet_promise_shared_ptr calc() { packet_promise_shared_ptr ptrPromisePacket(new packet_promise()); boost::mutex::scoped_lock l(mymap_mutex_); mymap_.insert(seq_promise_pair(counter_, ptrPromisePacket) ); counter_++; return ptrPromisePacket; } //calculate in a seperate thread and set_value(), loops forever void do_calc_in_thread() { while(true) { { boost::mutex::scoped_lock l(mymap_mutex_); seq_to_promise_map::iterator value_in_map_iter = mymap_.begin(); for (value_in_map_iter; value_in_map_iter != mymap_.end(); value_in_map_iter++) { unsigned long in_counter = value_in_map_iter-&gt;first; //printf("[%d] thread running set value\n", in_counter); Packet resultPacket(in_counter); value_in_map_iter-&gt;second-&gt;set_value(resultPacket); //make a copy mymap_.erase(value_in_map_iter); } } } } }; int main(int argc, char** argv) { Demo demo; unsigned long testCounter=0; while(true) { packet_promise_shared_ptr packetPromisePtr = demo.calc(); boost::system_time const timeout = boost::get_system_time() + boost::posix_time::milliseconds(500); boost::unique_future&lt; Packet &gt; pf = packetPromisePtr-&gt;get_future(); //often causes core-dump if (!pf.timed_wait_until(timeout)) { printf("[%d] error \n", testCounter); break; } else { Packet result = pf.get(); printf("[%d] ok : %d \n", testCounter, result.in); } testCounter++; } } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/4531 Trac 1.4.3 thijsterlouw@… Thu, 12 Aug 2010 03:16:52 GMT attachment set https://svn.boost.org/trac10/ticket/4531 https://svn.boost.org/trac10/ticket/4531 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">boostpromise.cpp</span> </li> </ul> Ticket Anthony Williams Fri, 22 Oct 2010 14:02:11 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/4531#comment:1 https://svn.boost.org/trac10/ticket/4531#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Fixed on trunk, revision 66146 </p> Ticket