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