[Boost-bugs] [Boost C++ Libraries] #5432: Deadlock with thread group's join_all and other modifier methods.

Subject: [Boost-bugs] [Boost C++ Libraries] #5432: Deadlock with thread group's join_all and other modifier methods.
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2011-04-06 13:45:02


#5432: Deadlock with thread group's join_all and other modifier methods.
------------------------------+---------------------------------------------
 Reporter: JDKunk@… | Owner: anthonyw
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: threads
  Version: Boost 1.47.0 | Severity: Showstopper
 Keywords: |
------------------------------+---------------------------------------------
 In boost::thread_group, the join_all function locks mutex m. So in other
 functions which use lock_guard, the lock_guard locks mutex m creating
 deadlock with multiple modifiers to the thread_group. The solution
 includes changing join_all so the mutex is only locked upon obtaining the
 next element of the thread_group's thread. Since a std::list is used,
 using an iterator while making it possible for another thread to modify
 the list is unacceptable. The solutions is to pop the std::list like a
 queue. So the front thread is dequeued while the mutex is locked, then the
 mutex is unlocked when the thread is joined. Thus it is possible for
 multiple threads to modify the thread_group while join_all has occurred.

 This code represents the current problem with the join_all function and
 other modifiers.
 {{{
 void join_all()
 {
   boost::shared_lock<shared_mutex> guard(m);
 ...

 void interrupt_all()
 {// This accessor has no problem with join_all
  boost::shared_lock<shared_mutex> guard(m);
 ...
 void remove_thread(thread* thrd)
 {// This modifier has no problem with join_all
   boost::lock_guard<shared_mutex> guard(m);
 ...
 }}}

 The below code is my minimal test case for this problem.
 {{{
 #include <boost/thread.hpp>

 boost::mutex lock;
 boost::thread * t[128];
 boost::thread_group tg;

 void run(int i) {
   lock.lock();
   // remove_thread locks the thread_group's mutex,
   // and join_all locks the thread_group's mutex
   // causing deadlock.
   tg.remove_thread(t[i]); // ***** Deadlock when tg.m is locked.
 }

 int main() {
   lock.lock();
   for( int i = 0; i < 128; ++i ) {
     t[i] = new boost::thread(run,i);
     tg.add_thread(t[i]);
   }
   lock.unlock();
   tg.join_all(); // ***** Deadlock when tg.m is locked.
 }
 }}}

 Finally here is my solution to the given problem.
 {{{
 void join_all()
 {
     boost::thread * t;
     while( 1 ) {
         {
             boost::lock_guard<shared_mutex> guard(m);
             if( threads.empty() )
               break;
             t = threads.front();
             threads.pop_front();
         }
         t->join();
     }
 }
 }}}

 Thank you, Jeff Kunkel

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/5432>
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:06 UTC