/* compile with: g++ -o deadlock-boost-signals2 deadlock-boost-signals2.cpp -lboost_signals -pthread run with gdb or valgrind: valgrind --tool=helgrind ./deadlock-boost-signals2 */ #include #include #include #include typedef boost::signals2::signal Signal; class SelfReference: private boost::noncopyable { public: boost::shared_ptr m_self; boost::shared_ptr m_signal; boost::signals2::connection m_conReleaseSelf; boost::signals2::connection m_conDoNothing; SelfReference() { m_signal = boost::make_shared(); } ~SelfReference() { // the first slot (ReleaseSelf) has been called; now the trackable object (this) // was released, while the second slot is locked assert(!m_conReleaseSelf.connected()); // the second slot is locked, and we enter a recursive (pthread: dead) lock assert(m_conDoNothing.connected()); m_conReleaseSelf.disconnect(); m_conDoNothing.disconnect(); // enter recursive (pthread: dead) lock again: assert(m_signal->empty()); } void ReleaseSelf() { m_self.reset(); } static void DoNothing() { } static void Run() { boost::shared_ptr signal; { boost::shared_ptr obj = boost::make_shared(); obj->m_self = obj; signal = obj->m_signal; obj->m_conReleaseSelf = signal->connect(Signal::slot_type(&SelfReference::ReleaseSelf, obj.get()).track(obj)); obj->m_conDoNothing = signal->connect(Signal::slot_type(&SelfReference::DoNothing)); } (*signal)(); } }; int main() { SelfReference::Run(); return 0; }