Boost logo

Boost Users :

Subject: [Boost-users] [Boost.Thread - promise::lazy_init()] core dump when sharing promise between threads
From: Thijs Terlouw (thijsterlouw_at_[hidden])
Date: 2010-08-09 23:20:57


I am experiencing core-dumps when sharing a boost::promise between two
threads. Full core-dump at the bottom.

My guess:
When one thread does promise.set_value(), I found that the set_value()
function of the promise class will execute lazy_init() and then lock a
guard. The other tread at the same time might execute
promise.get_future() which will also do a lazy_init(). It seems this
introduces a race-condition between the get_future() call and the
set_value() call: the local future_ptr in the promise class might be
reset() while it's being used? This has resulted in some coredumps (.
If I change /usr/local/boost_1_43_0/boost/thread/future.hpp to call
lazy_init() in the constructor of promise (around line 919, though it
will not be lazy anymore), the crashes disappear.

What's the right solution to this? Is it a bug in boost::promise or do
I use it wrong?

My use case:
I am writing an asynchronous library to be used inside synchronous
code. I use Boost.Asio + Boost.Thread futures/promises. One thread
(Asio) sends + receives packets. It will return a
boost::shared_ptr<packet_promise> where packet_promise is a
boost::promise<PacketType> when doing a write. When the Asio thread
receives, I do a set_value() to the promise. The main thread, the one
that did the request, will receive the shared_ptr to the
packet_promise and then execute get_value() on the promise.

My system:
Boost 1.43.0.
Linux 2.6.16.21-0.8
g++ (GCC) 4.1.0 (SUSE Linux)

=======================

full core-dump without calling the lazy_init() inside the promise's constructor:

#0 0xffffe410 in __kernel_vsyscall ()
#1 0xb7c377d0 in raise () from /lib/libc.so.6
#2 0xb7c38ea3 in abort () from /lib/libc.so.6
#3 0xb7c3101b in __assert_fail () from /lib/libc.so.6
#4 0x080f68b3 in ~mutex (this=0x81c8090) at
/usr/local/boost_1_43_0/boost/thread/pthread/mutex.hpp:46
#5 0x080fc375 in ~future_object_base (this=0x81c8080) at
/usr/local/boost_1_43_0/boost/thread/future.hpp:104
#6 0x080fc44c in ~future_object (this=0x81c8080) at
/usr/local/boost_1_43_0/boost/thread/future.hpp:290
#7 0x080cbd62 in
boost::checked_delete<boost::detail::future_object<lib_async::CQunPacket<lib_async::CQunEnvelope,
lib_async::CQunHeader, lib_async::CQunBody> > > (x=0x81c8080) at
/usr/local/boost_1_43_0/boost/checked_delete.hpp:34
#8 0x080cf724 in
boost::detail::sp_counted_impl_p<boost::detail::future_object<lib_async::CQunPacket<lib_async::CQunEnvelope,
lib_async::CQunHeader, lib_async::CQunBody> > >::dispose
(this=0x81a2f40) at
/usr/local/boost_1_43_0/boost/smart_ptr/detail/sp_counted_impl.hpp:78
#9 0x080c4586 in boost::detail::sp_counted_base::release (this=0x81a2f40)
    at /usr/local/boost_1_43_0/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:145
#10 0x080c45cc in ~shared_count (this=0xb4bc5b94) at
/usr/local/boost_1_43_0/boost/smart_ptr/detail/shared_count.hpp:217
#11 0x080c56cc in ~shared_ptr (this=0xb4bc5b90) at
/usr/local/boost_1_43_0/boost/smart_ptr/shared_ptr.hpp:169
#12 0x080d87c5 in
boost::shared_ptr<boost::detail::future_object<lib_async::CQunPacket<lib_async::CQunEnvelope,
lib_async::CQunHeader, lib_async::CQunBody> >
>::reset<boost::detail::future_object<lib_async::CQunPacket<lib_async::CQunEnvelope,
lib_async::CQunHeader, lib_async::CQunBody> > > (this=0x8250230,
p=0x823c780) at
/usr/local/boost_1_43_0/boost/smart_ptr/shared_ptr.hpp:392
#13 0x080fc8cf in
boost::promise<lib_async::CQunPacket<lib_async::CQunEnvelope,
lib_async::CQunHeader, lib_async::CQunBody> >::lazy_init (
    this=0x8250230) at /usr/local/boost_1_43_0/boost/thread/future.hpp:909
#14 0x080fc908 in
boost::promise<lib_async::CQunPacket<lib_async::CQunEnvelope,
lib_async::CQunHeader, lib_async::CQunBody> >::get_future
    (this=0x8250230) at /usr/local/boost_1_43_0/boost/thread/future.hpp:978
#15 0x080fd38e in SQunSession::recvAll (this=0xb4bc62dc,
error=@0xb4bc618e, TimeoutMs=500)
    at /data/home/thijs/git/yaaf/public/libasync/worker_async_demo.cpp:101
#16 0x080fd828 in AsyncDemoWorker::do_my_special_thing
(this=0x81b2080, session=@0xb4bc62dc)
    at /data/home/thijs/git/yaaf/public/libasync/worker_async_demo.cpp:240
#17 0x080fe7d6 in AsyncDemoWorker::onRequest (this=0x81b2080, sock=@0x819e3f8)
    at /data/home/thijs/git/yaaf/public/libasync/worker_async_demo.cpp:189
#18 0xb7f61da8 in yaaf::BaseWorker::run (this=0x81b2080) at
/data/home/thijs/git/yaaf/public/libyaaf/yaaf_worker.cpp:68
#19 0xb7f5d8cf in yaaf::Context::thread_entry_point (ctx=0x81b2088) at
/data/home/thijs/git/yaaf/public/libyaaf/yaaf_context.cpp:287
#20 0xb7f7934b in start_thread () from /lib/libpthread.so.0
#21 0xb7ccc65e in clone () from /lib/libc.so.6

line 101 in worker_async_demo.cpp looks like this:

100: packet_promise_ptr ppp_temp = (*it).first; //copy of shared
pointer, stored in a map
101: packet_future pf = ppp_temp->get_future(); //core-dump here

Thijs


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net