Opened 12 years ago
Closed 12 years ago
#4531 closed Bugs (fixed)
[Thread] ::promise shared between threads race-condition
Reported by: | Owned by: | Anthony Williams | |
---|---|---|---|
Milestone: | Boost 1.44.0 | Component: | thread |
Version: | Boost 1.43.0 | Severity: | Showstopper |
Keywords: | promise thread future lazy_init | Cc: |
Description
I believe I have discovered a problem with boost::promise when it's shared via threads. I described the problem (informally) on the 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++; } }
Attachments (1)
Change History (2)
by , 12 years ago
Attachment: | boostpromise.cpp added |
---|
comment:1 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Fixed on trunk, revision 66146