[Boost-bugs] [Boost C++ Libraries] #4531: [Thread] ::promise shared between threads race-condition

Subject: [Boost-bugs] [Boost C++ Libraries] #4531: [Thread] ::promise shared between threads race-condition
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2010-08-12 03:14:40


#4531: [Thread] ::promise shared between threads race-condition
---------------------------------------------+------------------------------
 Reporter: thijsterlouw@… | Owner: anthonyw
     Type: Bugs | Status: new
Milestone: Boost 1.44.0 | Component: thread
  Version: Boost 1.43.0 | Severity: Showstopper
 Keywords: promise thread future lazy_init |
---------------------------------------------+------------------------------
 I believe I have discovered a problem with boost::promise when it's shared
 via threads. I described the problem (informally) on the
 [http://lists.boost.org/boost-users/2010/08/61530.php boost-users-list].

 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.

 The test case can be made like this:
 {{{
 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
 }}}

 run like this:
 ./boostpromise

 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:

 {{{
 ...
 [11805] ok : 11815
 [11806] ok : 11816
 [11807] ok : 11817
 [11808] ok : 11818
 [11809] ok : 11819
 [11810] ok : 11820
 [11811] ok : 11821
 ...
 }}}


 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.

 {{{
 promise():
     future(),future_obtained(false)
 {
     lazy_init();
 }
 }}}

 back trace from coredump below:

 {{{
 (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<boost::detail::future_object<Packet> > (x=0x8174320)
     at /usr/local/boost_1_43_0/boost/checked_delete.hpp:34
 #8 0x0804dd04 in
 boost::detail::sp_counted_impl_p<boost::detail::future_object<Packet>
>::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<boost::detail::future_object<Packet>
>::reset<boost::detail::future_object<Packet> > (this=0x8171f68,
     p=0x8174260) at
 /usr/local/boost_1_43_0/boost/smart_ptr/shared_ptr.hpp:392
 #13 0x08061397 in boost::promise<Packet>::lazy_init (this=0x8171f68) at
 /usr/local/boost_1_43_0/boost/thread/future.hpp:909
 #14 0x080616e8 in boost::promise<Packet>::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)
 }}}

 ps, attaching the test file gave a TRAC error (
 {{{
 OperationalError: database is locked
 }}}
 so I just inline it here, boospromise.cpp :

 {{{
 #include <boost/thread.hpp>

 class Packet
 {
         public:
                 Packet(int i) : in(i) {}
                 int in;
 };

 typedef boost::promise< Packet > packet_promise;
 typedef boost::shared_ptr< packet_promise > packet_promise_shared_ptr;
 typedef std::pair< unsigned long, packet_promise_shared_ptr >
 seq_promise_pair;
 typedef std::map< unsigned long, packet_promise_shared_ptr >
 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(&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->first;
                                                 //printf("[%d] thread
 running set value\n", in_counter);
                                                 Packet
 resultPacket(in_counter);
 value_in_map_iter->second->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< Packet > pf =
 packetPromisePtr->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++;
         }

 }

 }}}

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/4531>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:04 UTC