红宝石异常如何导致mutices解锁?

Ste*_*tam 5 ruby multithreading mutex exception synchronize

最近,我一直在使用Ruby的线程,并且发现了一些意外的行为。在关键部分,调用raise会导致互斥体释放。我可以期望这种synchronize方法及其功能块,但似乎在lockunlock分别调用时也会发生。

例如,以下代码输出:

$ ruby testmutex.rb 
x sync
y sync
Run Code Online (Sandbox Code Playgroud)

...在y宇宙热死之前我一直希望能被阻止。

m = Mutex.new


x = Thread.new() do
  begin
    m.lock
      puts "x sync"
      sleep 5
      raise "x err"
      sleep 5
    m.unlock 
  rescue 
  end
end


y = Thread.new() do
  sleep 0.5
  m.lock
    puts "y sync"
  m.unlock 
end


x.join
y.join
Run Code Online (Sandbox Code Playgroud)

为什么即使从未执行过x线程中的m.unlock,也允许y线程运行?

Phr*_*ogz 4

请注意,如果您删除 和raise,则unlock行为x是相同的。因此,您会遇到这样的情况:x线程锁定互斥锁,然后线程结束,互斥锁被解锁。

m = Mutex.new
Thread.new{ m.lock; p m.locked? }.join
#=> true

p m.locked?
#=> false
Run Code Online (Sandbox Code Playgroud)

因此我们看到这种情况与 无关raise。因为您begin/rescue的 周围有一个块,所以您只需比其他情况提前 5 秒raise退出线程即可。x

据推测,解释器会跟踪线程锁定的任何互斥体,并在线程终止时自动有意地解锁它们。(但是,我无法通过源代码检查来支持这一点。这只是基于行为的猜测。)