さかいといいます

Timeout#timeout内でConditionVariable#waitを実行しタイムアウトになると、
Mutexがunlockされたままになってしまいます。

  require 'timeout'
  require 'thread'
  
  mutex = Mutex.new
  resource = ConditionVariable.new
  
  mutex.synchronize{
    begin
      timeout(0.01){
        resource.wait(mutex)
      }
    rescue Timeout::Error
      p mutex.locked? #=> false
    end
  }

# そもそも、この2つを組み合わせるのが想定外なのかもしれませんが、
# 幾つかのスレッドライブラリ (e.g. pthread, gthread, SRFI-18, Win32, etc) では
# timeoutを指定してwaitすることが出来るので、
# Rubyのスレッドでも同じことをしたかったのです。

最初は以下のように単にbegin/ensureを使うよう変更すればよいのかと思ったのですが、
ensure節まで到達した後 mutex.lock を実行する直前のタイミングで
Timeoutによって割り込まれる可能性も考慮する必要があるのでしょうか……

Index: lib/thread.rb
===================================================================
RCS file: /src/ruby/lib/thread.rb,v
retrieving revision 1.16
diff -u -p -r1.16 thread.rb
--- lib/thread.rb 16 Nov 2003 01:53:12 -0000	1.16
+++ lib/thread.rb 25 May 2004 14:16:00 -0000
@@ -189,11 +189,14 @@ class ConditionVariable
   # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
   #
   def wait(mutex)
-    mutex.exclusive_unlock do
-      @waiters.push(Thread.current)
-      Thread.stop
+    begin
+      mutex.exclusive_unlock do
+        @waiters.push(Thread.current)
+        Thread.stop
+      end
+    ensure
+      mutex.lock
     end
-    mutex.lock
   end
   
   #

--
酒井 政裕 / Masahiro Sakai