Project

General

Profile

Actions

Bug #9432

closed

ThreadError [ Attempt to unlock a mutex which is locked by another thread ]

Added by rajesh (rajesh shanmugam) almost 11 years ago. Updated over 5 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
2.0.0
Backport:
[ruby-core:59894]

Description

I use ruby-2.0.0-p247. I seem to get this issue frequently in threaded environment. (Sidekiq)

I am not very sure if it a ruby thread issue as such or something I am doing wrong. If there is any more details you need I would be happy to provide you.

Operating system: Ubuntu

Trace

/home/ubuntu/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/thread.rb:188:in `synchronize'
/home/ubuntu/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/thread.rb:188:in `block in pop'
/home/ubuntu/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/thread.rb:187:in `handle_interrupt'
/home/ubuntu/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/thread.rb:187:in `pop'

Regards
Rajesh

Updated by normalperson (Eric Wong) almost 11 years ago

I use ruby-2.0.0-p247. I seem to get this issue frequently in threaded
environment. (Sidekiq)

I am not very sure if it a ruby thread issue as such or something I am
doing wrong. If there is any more details you need I would be happy to
provide you.

Have you contacted the sidekiq author about this?

Updated by nagachika (Tomoyuki Chikanaga) over 10 years ago

Hello, rajesh.

Thank you for your report.
Could you try to reproduce it with 2.1 and/or trunk?

Updated by aaron@serendipity.cx (Aaron Stone) almost 10 years ago

Note: Sidekiq does not appear to be using eventmachine, which has a similar bug at #9132. Any ideas on what is going on here? I can reproduce the bug from all releases of Ruby 2.0.0pxxx including 2.0.0p598.

Updated by normalperson (Eric Wong) almost 10 years ago

Can you show us a small test case? Which version of Sidekiq?

Note: this issue seems to not affect Ruby 2.1+ because thread.rb was
rewritten in C. I looked briefly and #9132 but I'd rather deal
with issues in pure Ruby or C, not C++.

Updated by hsbt (Hiroshi SHIBATA) almost 10 years ago

  • Tracker changed from Backport to Bug
  • Project changed from Backport200 to Ruby master
  • ruby -v set to 2.0.0

Updated by aaron@serendipity.cx (Aaron Stone) almost 10 years ago

The error also shows up here: https://github.com/iconara/cql-rb/issues/68

This is not an issue with the applications or the gems, or that eventmachine is written in C++. It's an MRI Ruby problem in the 2.0 implementation of Queue.pop, which is different than the 1.9.3 implementation that does not have this problem.

Ruby 2.0 is a widely deployed and supported version.
I'd really appreciate if someone upstream would take this bug report seriously.

Updated by aaron@serendipity.cx (Aaron Stone) almost 10 years ago

In Ruby 1.9.3, thread.rb has Queue.pop defined as:

183   def pop(non_block=false)
184     @mutex.synchronize{
185       while true
186         if @que.empty?
187           raise ThreadError, "queue empty" if non_block
188           @waiting.push Thread.current
189           @mutex.sleep
190         else
191           return @que.shift
192         end
193       end
194     }
195   end

In Ruby 2.0, thread.rb has Queue.pop defined as:

186   def pop(non_block=false)
187     Thread.handle_interrupt(StandardError => :on_blocking) do
188       @mutex.synchronize do
189         while true
190           if @que.empty?
191             if non_block
192               raise ThreadError, "queue empty"
193             else
194               begin
195                 @num_waiting += 1
196                 @cond.wait @mutex
197               ensure
198                 @num_waiting -= 1
199               end
200             end
201           else
202             return @que.shift
203           end
204         end
205       end
206     end
207   end

The use of ConditionVariable is new in 2.0 vs. 1.9.3, and I think it is causing the problem. In 1.9.3, Queue.push itself walks its @waiting array to find and wake up a thread that will consume the just-pushed element. In 2.0, Queue.push calls @cond.signal which then goes and looks for a thread to wake up.

Ok, here's the most salient difference:
In 1.9.3, Queue.push calls thread.wakeup on a consuming thread.
In 2.0, Queue.push calls ConditionVariable.signal calls thread.run on a consuming thread.

The difference is that thread.run also executes the scheduler immediately.

In Ruby 2.1 and up, thread.rb does not exist - it appears to be rewritten in C.

Updated by aaron@serendipity.cx (Aaron Stone) over 9 years ago

Dear Ruby maintainers: this is still a problem. Please, help out here.

Actions #9

Updated by jeremyevans0 (Jeremy Evans) over 5 years ago

  • Status changed from Open to Closed
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0