https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112016-04-18T13:00:41ZRuby Issue Tracking SystemRuby master - Bug #12298: Indeterministic ruby behavior when another thread is killedhttps://bugs.ruby-lang.org/issues/12298?journal_id=581392016-04-18T13:00:41Zrupert (Robert Pankowecki)robert.pankowecki@gmail.com
<ul></ul><p>Related Honeybadger bug: <a href="https://github.com/honeybadger-io/honeybadger-ruby/issues/186" class="external">https://github.com/honeybadger-io/honeybadger-ruby/issues/186</a></p> Ruby master - Bug #12298: Indeterministic ruby behavior when another thread is killedhttps://bugs.ruby-lang.org/issues/12298?journal_id=581552016-04-19T18:47:56Zdrbrain (Eric Hodel)drbrain@segment7.net
<ul><li><strong>File</strong> <a href="/attachments/5909">a.txt</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/5909/a.txt">a.txt</a> added</li><li><strong>File</strong> <a href="/attachments/5910">b.txt</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/5910/b.txt">b.txt</a> added</li><li><strong>File</strong> <a href="/attachments/5911">12998.rb</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/5911/12998.rb">12998.rb</a> added</li><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul><p>This is not a ruby bug. Thread scheduling is inherently non-deterministic.</p>
<p>Sometimes you'll switch to the work thread before reaching rb_thread_terminate_all which allows the ensure to run, sometimes you won't.</p>
<p>I've attached a reduced test case and logs from ruby built with THREAD_DEBUG=1</p>
<p>Honeybadger should probably not sleep in ensure as a way to reduce thrashing when work finishes (I'm guessing that's what they use the sleep for) and should use a different mechanism instead.</p> Ruby master - Bug #12298: Indeterministic ruby behavior when another thread is killedhttps://bugs.ruby-lang.org/issues/12298?journal_id=581662016-04-20T06:09:12Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>Hmm. Although the report was already rejected, and even if we all may agree that<br>
the honeybadger code was not brilliant, I feel that the overall issue here in<br>
regards to Threads may be useful for more people in the future too.</p>
<p>For instance, without the blog explanation, where else would you find that much<br>
information about ruby code used for "real"? From the official documentation<br>
of Threads?</p>
<pre><code>http://ruby-doc.org/core-2.3.0/Thread.html
</code></pre>
<p>The documentation is not bad at all, mind you, but the blog semi-taught me<br>
more than the documentation would.</p>
<p>There may also be small improvements. We have instance methods like:</p>
<p>"See also the instance methods alive? and stop?"</p>
<p>In the code he checked whether the thread was aborting:</p>
<pre><code>Thread.current.status == "aborting"
</code></pre>
<p>This could be simplified if the ruby code would allow<br>
for this check:</p>
<pre><code>Thread.current.aborting?
</code></pre>
<p>Or perhaps even</p>
<pre><code>Thread.aborting?
</code></pre>
<p>(I do not really know Threads that well that I can suggest an API<br>
that makes sense / is logical.)</p>
<p>Without that block, I would probably have never been able to figure<br>
out that a thread is not just alive or dead but may be in between<br>
the two like the schroedinger cat.</p> Ruby master - Bug #12298: Indeterministic ruby behavior when another thread is killedhttps://bugs.ruby-lang.org/issues/12298?journal_id=581682016-04-20T07:35:20Zrupert (Robert Pankowecki)robert.pankowecki@gmail.com
<ul></ul><p>Eric Hodel wrote:</p>
<blockquote>
<p>This is not a ruby bug. Thread scheduling is inherently non-deterministic.</p>
<p>Sometimes you'll switch to the work thread before reaching rb_thread_terminate_all which allows the ensure to run, sometimes you won't.</p>
</blockquote>
<p>I get that. But why does Ruby wait for the second thread to finish? Or is it that Ruby always waits for those threads to finish, but the Thread gets un-catchable Exception and only runs the ensure blocks and that's what is happening?</p> Ruby master - Bug #12298: Indeterministic ruby behavior when another thread is killedhttps://bugs.ruby-lang.org/issues/12298?journal_id=581712016-04-20T18:17:13Zdrbrain (Eric Hodel)drbrain@segment7.net
<ul></ul><p>In ruby_cleanup:</p>
<p>First we mark the main thread as killed: <a href="https://github.com/ruby/ruby/blob/trunk/eval.c#L186" class="external">https://github.com/ruby/ruby/blob/trunk/eval.c#L186</a></p>
<p>Then we kill all threads: <a href="https://github.com/ruby/ruby/blob/trunk/eval.c#L191" class="external">https://github.com/ruby/ruby/blob/trunk/eval.c#L191</a></p>
<p>Then we start at_exit hooks: (via ruby_finalize_1) <a href="https://github.com/ruby/ruby/blob/trunk/eval.c#L222" class="external">https://github.com/ruby/ruby/blob/trunk/eval.c#L222</a></p>
<p>Sometimes ruby switches to the killed thread right away, so it sleeps in the ensure in your test case. It can't switch back to the main thread because it is marked as killed.</p>
<p>Sometimes ruby doesn't switch to the killed thread so it gets two signals and never sleeps (because the second arrives in the ensure when it tries to sleep).</p>