id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc 9319,Using future continuations (.then) leads to deadlock waiting to acquire an already held mutex,arichardatwork@…,viboes,"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 -L -lboost_thread -lboost_system futtest.cpp {{{ // futtest.cpp #include #define BOOST_THREAD_VERSION 4 #include #include #include #include #include #include using namespace boost; typedef shared_ptr< promise > 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 & 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()); thread t(boost::bind(foo, p)); future 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 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::lock (this=0x7fe6999f3a80) at build/common/externals/boost/boost_build/install/include/boost/thread/lock_types.hpp:346 #6 0x0000000000410f41 in boost::unique_lock::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::get (this=0x19e30f0) at build/common/externals/boost/boost_build/install/include/boost/thread/future.hpp:647 #9 0x0000000000411d4f in boost::future::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 >::operator()&), boost::_bi::list1&> > (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&), boost::_bi::list1 > >::operator() > (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, void, boost::_bi::bind_t&), boost::_bi::list1 > > >::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, void, boost::_bi::bind_t&), boost::_bi::list1 > > >::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::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::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 > > >::operator() >), 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 >), boost::_bi::list1 to continue, or q to quit--- > > > >::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::list1 > > > > >::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 }}}",Bugs,closed,Boost 1.55.0,thread,Boost 1.54.0,Problem,fixed,future continuation,