Subject: [Boost-bugs] [Boost C++ Libraries] #9319: Using future continuations (.then) leads to deadlock waiting to acquire an already held mutex
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2013-10-29 20:11:54
#9319: Using future continuations (.then) leads to deadlock waiting to acquire an
already held mutex
---------------------------------+----------------------
Reporter: arichardatwork@⦠| Owner: anthonyw
Type: Bugs | Status: new
Milestone: To Be Determined | Component: thread
Version: Boost 1.54.0 | Severity: Problem
Keywords: future continuation |
---------------------------------+----------------------
I encountered a problem with a continuation attempting to relock a mutex
which is already held by the code which launched the continuation.
(Leading to a deadlock of sorts).
Here is an example test program. I realize that in this trivial example
some of my choices (like using a promise instead of a packaged task)
probably don't make sense, but this is distilled out of a more complex
block of code.
gcc version 4.6.3
Boost version 1.54.0
g++ -g -I <path to boost include> -L <path to boost lib> -lboost_thread
-lboost_system futtest.cpp
{{{
// futtest.cpp
#include <iostream>
#define BOOST_THREAD_VERSION 4
#include <boost/thread/future.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/chrono.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
using namespace boost;
typedef shared_ptr< promise<int> > IntPromise;
void foo(IntPromise p)
{
std::cout << "foo" << std::endl;
p->set_value(123); // This line locks the future's mutex, then calls
the continuation with the mutex already locked.
}
void bar(future<int> & fooResult)
{
std::cout << "bar" << std::endl;
int i = fooResult.get(); // Code hangs on this line (Due to future
already being locked by the set_value call)
std::cout << "i: " << i << std::endl;
}
int main()
{
IntPromise p(new promise<int>());
thread t(boost::bind(foo, p));
future<int> f1 = p->get_future();
f1.then(launch::deferred, boost::bind(bar, _1));
t.join();
}
}}}
When this is run, this starts the 'foo' method on another thread. Foo sets
the value of the promise (which locks the mutex on the future), which then
launches the continuation 'bar' (on the same thread). The continuation
calls 'get' on the future which attempts to relock the future (which is
still locked from the promise being set, and the program hangs
indefinitely.
Alternately, if the continuation is added as shown below:
{{{
future<void> f2 = f1.then(launch::deferred, boost::bind(bar, _1));
f2.get();
}}}
Then the code will generally work, but theris a race condition, because if
the f2.get() call doesn't happen before set_value is called, then the
deadlock still occurs. (You can see this by injecting a sleep before the
f2.get() call.
Here is a stack trace of the original program.
{{{
THREAD 1
#0 0x000000362a20bae5 in pthread_cond_wait@@GLIBC_2.3.2 () from
/lib64/libpthread.so.0
#1 0x00007fe699c356bb in boost::condition_variable::wait ()
from
build/common/externals/boost/boost_build/install/lib/libboost_thread.so.1.54.0
#2 0x00007fe699c35a0e in boost::thread::join_noexcept() ()
from
build/common/externals/boost/boost_build/install/lib/libboost_thread.so.1.54.0
#3 0x000000000040d173 in boost::thread::join (this=0x7fff1ed084f0)
at
build/common/externals/boost/boost_build/install/include/boost/thread/detail/thread.hpp:756
#4 0x0000000000409b4b in main () at futtest.cpp:34
THREAD 2
[Switching to thread 2 (Thread 0x7fe6999f4700 (LWP 11875))]
#0 0x000000362a20e34d in __lll_lock_wait () from /lib64/libpthread.so.0
(gdb) bt
#0 0x000000362a20e34d in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x000000362a209f97 in _L_lock_863 () from /lib64/libpthread.so.0
#2 0x000000362a209deb in pthread_mutex_lock () from
/lib64/libpthread.so.0
#3 0x000000000040adf1 in pthread_mutex_lock (m=0x19e3128)
at
build/common/externals/boost/boost_build/install/include/boost/thread/pthread/mutex.hpp:61
#4 boost::mutex::lock (this=0x19e3128) at
build/common/externals/boost/boost_build/install/include/boost/thread/pthread/mutex.hpp:113
#5 0x0000000000410da4 in boost::unique_lock<boost::mutex>::lock
(this=0x7fe6999f3a80)
at
build/common/externals/boost/boost_build/install/include/boost/thread/lock_types.hpp:346
#6 0x0000000000410f41 in boost::unique_lock<boost::mutex>::unique_lock
(this=0x7fe6999f3a80, m_=...)
at
build/common/externals/boost/boost_build/install/include/boost/thread/lock_types.hpp:124
#7 0x000000000040dc95 in boost::detail::future_object_base::wait
(this=0x19e30f0, rethrow=true)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:366
#8 0x0000000000417d17 in boost::detail::future_object<int>::get
(this=0x19e30f0)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:647
#9 0x0000000000411d4f in boost::future<int>::get (this=0x19e3670)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:1577
#10 0x00000000004099cb in bar (fooResult=...) at futtest.cpp:24
#11 0x0000000000427eee in boost::_bi::list1<boost::arg<1>
>::operator()<void (*)(boost::future<int>&),
boost::_bi::list1<boost::future<int>&> > (this=0x19e3688, f=@0x19e3680,
a=...) at
build/common/externals/boost/boost_build/install/include/boost/bind/bind.hpp:253
#12 0x0000000000426aea in boost::_bi::bind_t<void, void
(*)(boost::future<int>&), boost::_bi::list1<boost::arg<1> >
>::operator()<boost::future<int> > (this=0x19e3680, a1=...) at
build/common/externals/boost/boost_build/install/include/boost/bind/bind_template.hpp:32
#13 0x0000000000425349 in
boost::detail::future_deferred_continuation<boost::future<int>, void,
boost::_bi::bind_t<void, void (*)(boost::future<int>&),
boost::_bi::list1<boost::arg<1> > > >::execute (this=0x19e3570, lck=...)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:3649
#14 0x0000000000425316 in
boost::detail::future_deferred_continuation<boost::future<int>, void,
boost::_bi::bind_t<void, void (*)(boost::future<int>&),
boost::_bi::list1<boost::arg<1> > > >::launch_continuation
(this=0x19e3570, lk=...)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:3644
#15 0x000000000040d915 in
boost::detail::future_object_base::do_continuation (this=0x19e30f0,
lock=...)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:286
#16 0x000000000040da61 in
boost::detail::future_object_base::mark_finished_internal (this=0x19e30f0,
lock=...)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:315
#17 0x0000000000417ab4 in
boost::detail::future_object<int>::mark_finished_with_result_internal
(this=0x19e30f0, result_=123, lock=...)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:614
#18 0x0000000000411be4 in boost::promise<int>::set_value (this=0x19e30d0,
r=123)
at
build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:1803
#19 0x0000000000409995 in foo (p=...) at futtest.cpp:18
#20 0x0000000000427e58 in
boost::_bi::list1<boost::_bi::value<boost::shared_ptr<boost::promise<int>
> > >::operator()<void (*)(boost::shared_ptr<boost::promise<int> >),
boost::_bi::list0> (this=0x19e3400, f=@0x19e33f8, a=...)
at
build/common/externals/boost/boost_build/install/include/boost/bind/bind.hpp:253
#21 0x0000000000426a9f in boost::_bi::bind_t<void, void
(*)(boost::shared_ptr<boost::promise<int> >),
boost::_bi::list1<boost::_bi::value---Type <return> to continue, or q
<return> to quit---
<boost::shared_ptr<boost::promise<int> > > > >::operator()
(this=0x19e33f8)
at
build/common/externals/boost/boost_build/install/include/boost/bind/bind_template.hpp:20
#22 0x0000000000425262 in
boost::detail::thread_data<boost::_bi::bind_t<void, void
(*)(boost::shared_ptr<boost::promise<int> >),
boost::_bi::list1<boost::_bi::value<boost::shared_ptr<boost::promise<int>
> > > > >::run (this=0x19e3240)
at
build/common/externals/boost/boost_build/install/include/boost/thread/detail/thread.hpp:117
#23 0x00007fe699c342fa in thread_proxy () from
build/common/externals/boost/boost_build/install/lib/libboost_thread.so.1.54.0
#24 0x000000362a207d90 in start_thread () from /lib64/libpthread.so.0
#25 0x0000003629af119d in clone () from /lib64/libc.so.6
}}}
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/9319> 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:14 UTC