Boost C++ Libraries: Ticket #5432: Deadlock with thread group's join_all and other modifier methods. https://svn.boost.org/trac10/ticket/5432 <p> 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. </p> <p> This code represents the current problem with the join_all function and other modifiers. </p> <pre class="wiki">void join_all() { boost::shared_lock&lt;shared_mutex&gt; guard(m); ... void interrupt_all() {// This accessor has no problem with join_all boost::shared_lock&lt;shared_mutex&gt; guard(m); ... void remove_thread(thread* thrd) {// This modifier has no problem with join_all boost::lock_guard&lt;shared_mutex&gt; guard(m); ... </pre><p> The below code is my minimal test case for this problem. </p> <pre class="wiki">#include &lt;boost/thread.hpp&gt; 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 &lt; 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. } </pre><p> Finally here is my solution to the given problem. </p> <pre class="wiki">void join_all() { boost::thread * t; while( 1 ) { { boost::lock_guard&lt;shared_mutex&gt; guard(m); if( threads.empty() ) break; t = threads.front(); threads.pop_front(); } t-&gt;join(); } } </pre><p> Thank you, Jeff Kunkel </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/5432 Trac 1.4.3 Jeff Kunkel <JDKunk@…> Wed, 06 Apr 2011 14:17:56 GMT <link>https://svn.boost.org/trac10/ticket/5432#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/5432#comment:1</guid> <description> <p> Woops, I made a mistake on my test case. I never unlocked the mutex in run, and I never returned from main. </p> <pre class="wiki">#include &lt;boost/thread.hpp&gt; 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. lock.unlock(); } int main() { lock.lock(); for( int i = 0; i &lt; 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. return 0; } </pre> </description> <category>Ticket</category> </item> <item> <author>Jeff Kunkel <JDKunk@…></author> <pubDate>Wed, 06 Apr 2011 21:01:34 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/5432 https://svn.boost.org/trac10/ticket/5432 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">thread_group.hpp</span> </li> </ul> <p> I revised the solution to the problem. The join all method will copy the current thread list. The join all method will then join all the current threads in the list. All modifications to the list will be ignored until join_all exits and is called again. Other solutions are welcome, but this is a classic reader-writer problem. </p> Ticket viboes Wed, 11 May 2011 06:17:18 GMT component changed https://svn.boost.org/trac10/ticket/5432#comment:2 https://svn.boost.org/trac10/ticket/5432#comment:2 <ul> <li><strong>component</strong> <span class="trac-field-old">threads</span> → <span class="trac-field-new">thread</span> </li> </ul> Ticket viboes Sun, 04 Dec 2011 19:02:09 GMT owner, status changed; cc set https://svn.boost.org/trac10/ticket/5432#comment:3 https://svn.boost.org/trac10/ticket/5432#comment:3 <ul> <li><strong>cc</strong> <span class="trac-author">viboes</span> added </li> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">viboes</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> <p> Your examples is an example of deadlock, but I'm not sure if we can say that there is a deadlock in Boost.Thread. </p> <p> Your solution seems to not be one, as the thread calling join-all will think that all the thread in the group are joined and this could be not the case as other thread could be added to it. </p> <p> I think that the best the library can do is to move one thread group to another. </p> <p> Maybe the documentation should stay that access to the thread group from any thread in the group will result in a deadlock. </p> <p> Other solutions? </p> <p> BTW, I don't think this is a Showstopper as you can remove the thread from the group after joining all the threads. </p> Ticket viboes Wed, 07 Dec 2011 22:48:32 GMT type, severity changed https://svn.boost.org/trac10/ticket/5432#comment:4 https://svn.boost.org/trac10/ticket/5432#comment:4 <ul> <li><strong>type</strong> <span class="trac-field-old">Bugs</span> → <span class="trac-field-new">Support Requests</span> </li> <li><strong>severity</strong> <span class="trac-field-old">Showstopper</span> → <span class="trac-field-new">Problem</span> </li> </ul> <p> Moved to support request until resolution clarified. </p> Ticket viboes Sat, 07 Jan 2012 23:15:14 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/5432#comment:5 https://svn.boost.org/trac10/ticket/5432#comment:5 <ul> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">worksforme</span> </li> </ul> <p> Closed as the deadlock is not in the library. Please reopen if you don't agree with resolution. </p> Ticket