From: m_seki@... Date: 2000-03-16T09:05:16+09:00 Subject: [ruby-dev:9445] thread.rb 咳といいます。 1.4.3 のthread.rb を読んでました。 thread.rb に入っているスレッドの同期メカニズムなんですが、 (Queue, Mutex等)資源待ちのスレッドがだれかに exit された場合、 run や wakeup するときに失敗してしまうと思います。 require 'thread' def reader(q) Thread.new do q.pop end end q = Queue.new t1 = reader(q) t2 = reader(q) t1.exit # まとめてにkillされたりTimeoutでkillされたり‥ q.push('hello') → ThreadError ThreadGroupなどでまとめてkillできるようになると、 こういう局面がよくありそうな気がするのですが問題に ならないでしょうか? またMutex, Queueでは@waitingの先頭のスレッドだけを run/wakeup しますが、@waiting中のすべてのスレッドをwakeupしないとまずい 局面がないですか。 起こされたスレッドが資源を獲得する前にこけちゃうとか。 # 考えなくていいのかな。よくわかんない。 以下 wakeup/run で ThreadError を rescue するパッチです。 QueueとMutexは試しましたがSizedQueue、状態変数はやってません。 # あっているか不安。 *** /usr/local/lib/ruby/1.4/thread.rb Mon Sep 13 13:32:35 1999 --- thread.rb Thu Mar 16 08:45:12 2000 *************** *** 63,72 **** def unlock return unless @locked Thread.critical = true - t = @waiting.shift @locked = false Thread.critical = false - t.run if t self end --- 63,76 ---- def unlock return unless @locked Thread.critical = true @locked = false + begin + t = @waiting.shift + t.wakeup if t + rescue ThreadError + retry + end Thread.critical = false self end *************** *** 82,90 **** def exclusive_unlock return unless @locked Thread.exclusive do - t = @waiting.shift @locked = false ! t.wakeup if t yield end self --- 86,98 ---- def exclusive_unlock return unless @locked Thread.exclusive do @locked = false ! begin ! t = @waiting.shift ! t.wakeup if t ! rescue ThreadError ! retry ! end yield end self *************** *** 105,112 **** end def signal ! t = @waiters.shift ! t.run if t end def broadcast --- 113,124 ---- end def signal ! begin ! t = @waiters.shift ! t.run if t ! rescue ThreadError ! retry ! end end def broadcast *************** *** 116,122 **** @waiters.clear end for t in waiters0 ! t.run end end end --- 128,137 ---- @waiters.clear end for t in waiters0 ! begin ! t.run ! rescue ThreadError ! end end end end *************** *** 133,141 **** def push(obj) Thread.critical = true @que.push obj ! t = @waiting.shift Thread.critical = false - t.run if t end alias enq push --- 148,160 ---- def push(obj) Thread.critical = true @que.push obj ! begin ! t = @waiting.shift ! t.wakeup if t ! rescue ThreadError ! retry ! end Thread.critical = false end alias enq push *************** *** 201,208 **** @max = max Thread.critical = false diff.times do ! t = @queue_wait.shift ! t.run if t end end max --- 220,231 ---- @max = max Thread.critical = false diff.times do ! begin ! t = @queue_wait.shift ! t.run if t ! rescue ThreadError ! retry ! end end end max *************** *** 221,228 **** def pop(*args) Thread.critical = true if @que.length < @max ! t = @queue_wait.shift ! t.run if t end super end --- 244,255 ---- def pop(*args) Thread.critical = true if @que.length < @max ! begin ! t = @queue_wait.shift ! t.run if t ! rescue ThreadError ! retry ! end end super end