Boost C++ Libraries: Ticket #7668: thread_group::join_all() should check whether its threads are joinable https://svn.boost.org/trac10/ticket/7668 <p> If a thread in a thread_group is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined, thread_group::join_all() throws invalid_argument. Since it's impossible to enumerate the threads in a thread_group, it should ensure on its own that every thread is joinable(). </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/7668 Trac 1.4.3 viboes Fri, 09 Nov 2012 20:26:19 GMT owner, status, description changed https://svn.boost.org/trac10/ticket/7668#comment:1 https://svn.boost.org/trac10/ticket/7668#comment:1 <ul> <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> <li><strong>description</strong> modified (<a href="/trac10/ticket/7668?action=diff&amp;version=1">diff</a>) </li> </ul> Ticket viboes Fri, 09 Nov 2012 20:51:52 GMT milestone changed https://svn.boost.org/trac10/ticket/7668#comment:2 https://svn.boost.org/trac10/ticket/7668#comment:2 <ul> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.53.0</span> </li> </ul> <p> Committed in trunk revision <a class="changeset" href="https://svn.boost.org/trac10/changeset/81270" title="Thread: manage with ref #7668">[81270]</a>. </p> Ticket anonymous Sun, 11 Nov 2012 19:02:38 GMT <link>https://svn.boost.org/trac10/ticket/7668#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:3</guid> <description> <p> What are users suppose to do in the meantime? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sat, 17 Nov 2012 13:03:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:4</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7668#comment:3" title="Comment 3">anonymous</a>: </p> <blockquote class="citation"> <p> What are users suppose to do in the meantime? </p> </blockquote> <p> What do you mean? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 02 Dec 2012 10:46:24 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/7668#comment:5 https://svn.boost.org/trac10/ticket/7668#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">fixed</span> </li> </ul> <p> Committed revision <a class="changeset" href="https://svn.boost.org/trac10/changeset/81667" title="Thread: merge from trunk 1.53">[81667]</a>. </p> Ticket mendola@… Fri, 07 Dec 2012 19:28:01 GMT <link>https://svn.boost.org/trac10/ticket/7668#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:6</guid> <description> <p> The fix doesn't solve the problem indeed the thread can detach itself so between the call joinable() and join() the precondition would not be valid anymore. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 07 Dec 2012 19:45:34 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:7</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7668#comment:6" title="Comment 6">mendola@…</a>: </p> <blockquote class="citation"> <p> The fix doesn't solve the problem indeed the thread can detach itself so between the call joinable() and join() the precondition would not be valid anymore. </p> </blockquote> <p> From my point of view a thread in a thread_group is owned by the thread group. Any direct operation on a thread belonging to the thread group falls in undefined behavior. From the documentation </p> <pre class="wiki">Member function create_thread() template&lt;typename F&gt; thread* create_thread(F threadfunc); Effects: Create a new boost::thread object as-if by new thread(threadfunc) and add it to the group. Postcondition: this-&gt;size() is increased by one, the new thread is running. Returns: A pointer to the new boost::thread object. Member function add_thread() void add_thread(thread* thrd); Precondition: The expression delete thrd is well-formed and will not result in undefined behaviour. Effects: Take ownership of the boost::thread object pointed to by thrd and add it to the group. Postcondition: this-&gt;size() is increased by one. </pre> </description> <category>Ticket</category> </item> <item> <author>Andrew Molyneux <andrew.molyneux@…></author> <pubDate>Thu, 10 Jan 2013 11:32:51 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:8</guid> <description> <p> I don't think there does have to be a direct operation on the thread - the thread can just end normally (by returning from the function), which unless I'm very much mistaken makes it non-joinable. This could happen at any time, so I believe the code committed in revision 81270 has a race condition. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Thu, 10 Jan 2013 17:27:48 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:9</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7668#comment:8" title="Comment 8">Andrew Molyneux &lt;andrew.molyneux@…&gt;</a>: </p> <blockquote class="citation"> <p> I don't think there does have to be a direct operation on the thread - the thread can just end normally (by returning from the function), which unless I'm very much mistaken makes it non-joinable. This could happen at any time, so I believe the code committed in revision 81270 has a race condition. </p> </blockquote> <p> No. I thread that finish normally is still joinable. From where are you deducing this? </p> </description> <category>Ticket</category> </item> <item> <author>Andrew Molyneux <andrew.molyneux@…></author> <pubDate>Thu, 10 Jan 2013 19:51:51 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:10 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:10</guid> <description> <blockquote class="citation"> <p> No. I thread that finish normally is still joinable. From where are you deducing this? </p> </blockquote> <p> I thought I'd observed it, but on further investigation the situation is a bit more complex. My code is actually using thread::timed_join() periodically, to check if the thread is still running. I've distilled it down to the following code, which triggers the behaviour that surprised me: </p> <div class="wiki-code"><div class="code"><pre><span class="kt">void</span> <span class="nf">threadFunction</span><span class="p">()</span> <span class="p">{</span> <span class="n">boost</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">millisec</span><span class="p">(</span><span class="mi">100</span><span class="p">));</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span> <span class="n">boost</span><span class="o">::</span><span class="kr">thread</span> <span class="n">theThread</span><span class="p">(</span><span class="n">threadFunction</span><span class="p">);</span> <span class="c1">// Wait long enough to be fairly certain that the thread has finished</span> <span class="n">boost</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">millisec</span><span class="p">(</span><span class="mi">200</span><span class="p">));</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">theThread</span><span class="p">.</span><span class="n">timed_join</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">millisec</span><span class="p">(</span><span class="mi">0</span><span class="p">)))</span> <span class="p">{</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;Thread still running???&quot;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">theThread</span><span class="p">.</span><span class="n">join</span><span class="p">();</span> <span class="p">}</span> </pre></div></div><p> When I run that code, I get an exception on the call to theThread.join(), complaining that the thread is not joinable. It seems that after theThread.timed_join() succeeds, the thread is no longer joinable. Is this the expected behaviour? </p> <p> By the way, my environment is Windows 7 64-bit, but 32-bit Boost, with Visual Studio 2005 and Boost 1.52.0). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Thu, 10 Jan 2013 20:19:06 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:11</guid> <description> <p> Yes it is indeed. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Thu, 10 Jan 2013 21:04:09 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:12 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:12</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7668#comment:10" title="Comment 10">Andrew Molyneux &lt;andrew.molyneux@…&gt;</a>: </p> <blockquote class="citation"> <blockquote class="citation"> <p> No. I thread that finish normally is still joinable. From where are you deducing this? </p> </blockquote> <p> I thought I'd observed it, but on further investigation the situation is a bit more complex. My code is actually using thread::timed_join() periodically, to check if the thread is still running. I've distilled it down to the following code, which triggers the behaviour that surprised me: </p> <div class="wiki-code"><div class="code"><pre><span class="kt">void</span> <span class="nf">threadFunction</span><span class="p">()</span> <span class="p">{</span> <span class="n">boost</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">millisec</span><span class="p">(</span><span class="mi">100</span><span class="p">));</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span> <span class="n">boost</span><span class="o">::</span><span class="kr">thread</span> <span class="n">theThread</span><span class="p">(</span><span class="n">threadFunction</span><span class="p">);</span> <span class="c1">// Wait long enough to be fairly certain that the thread has finished</span> <span class="n">boost</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">sleep</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">millisec</span><span class="p">(</span><span class="mi">200</span><span class="p">));</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">theThread</span><span class="p">.</span><span class="n">timed_join</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">posix_time</span><span class="o">::</span><span class="n">millisec</span><span class="p">(</span><span class="mi">0</span><span class="p">)))</span> <span class="p">{</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;Thread still running???&quot;</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">theThread</span><span class="p">.</span><span class="n">join</span><span class="p">();</span> <span class="p">}</span> </pre></div></div><p> When I run that code, I get an exception on the call to theThread.join(), complaining that the thread is not joinable. It seems that after theThread.timed_join() succeeds, the thread is no longer joinable. Is this the expected behaviour? </p> </blockquote> <p> Yes, I confirm. </p> </description> <category>Ticket</category> </item> <item> <author>Andrew Molyneux <andrew.molyneux@…></author> <pubDate>Fri, 11 Jan 2013 14:27:34 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7668#comment:13 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7668#comment:13</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7668#comment:12" title="Comment 12">viboes</a>: </p> <blockquote class="citation"> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/7668#comment:10" title="Comment 10">Andrew Molyneux &lt;andrew.molyneux@…&gt;</a>: </p> <blockquote class="citation"> <p> [snip] </p> <p> When I run that code, I get an exception on the call to theThread.join(), complaining that the thread is not joinable. It seems that after theThread.timed_join() succeeds, the thread is no longer joinable. Is this the expected behaviour? </p> </blockquote> <p> Yes, I confirm. </p> </blockquote> <p> Excellent! Sorry for wasting your time with my ignorance. On reading the documentation again, it is clear that is the case. I've fixed my code now :-) </p> </description> <category>Ticket</category> </item> </channel> </rss>