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