From: Yusuke ENDOH Date: 2010-05-05T09:32:32+09:00 Subject: [ruby-dev:41155] Re: MonitorMixin::ConditionVariable#wait timeout 前田さん、akr さん 遠藤です。 2010年2月5日14:48 Shugo Maeda : >> Ruby 1.8 のころは timeout 引数が動作していたようなのですが、 >> Ruby 1.9 で timeout 引数がまた動作するようになる予定はあるのでしょうか。 >> メッセージからするとそのうち実装されるような感じがするのですが。 > > ::ConditionVariable#waitがtimeoutに対応しているようなので、引数を > そのまま渡すようにしたいと思います。 > ただ、戻り値については1.8と非互換になりますが、timeoutで返って来たのか > 判定する術がないので、常にtrueを返すことにしたいと思います。 > # ついでにドキュメントを追加します。 [Bug #2629] で ::ConditionVariable#wait の API 設計に race condition が あることがわかりました。 秒数ではなく絶対時刻で指定すべき (少なくとも、絶対時刻は受け付けるべき) ようです。また、timeout で帰ってきたかどうかを返り値として返した方が よいという指摘もあります。 絶対時刻を受け付けるためには thread.c を結構いろいろ変えないといけない ので、すでに feature freeze 後ということもあり、保守的ですが 1.9.2 では revert しようと思いますが、いかがでしょうか。 >> とりあえず wait にタイムアウトを入れて、ハングしないで test-all >> が最後までいくようにしようか、と思ったのですが、 >> MonitorMixin::ConditionVariable#wait の timeout 引数を指定すると >> timeout is not implemented yet というメッセージで >> NotImplementedError になってしまいます。 こっちの問題に関しては、タイミングに依存するので多少ださいですが、時間 指定の sleep を使えばもっと簡単になると思います。 test/ruby 以下にはこんなコードがたくさんあります。 ただ、このテストがテストしたいのが imap.idle のブロックからの途中脱出だ としたら、break するだけでいいかも? diff --git a/test/net/imap/test_imap.rb b/test/net/imap/test_imap.rb index 501298c..b1994b1 100644 --- a/test/net/imap/test_imap.rb +++ b/test/net/imap/test_imap.rb @@ -217,30 +217,18 @@ class IMAPTest < Test::Unit::TestCase begin imap = Net::IMAP.new("localhost", :port => port) begin - th = Thread.current - m = Monitor.new in_idle = false - exception_raised = false - c = m.new_cond - Thread.start do - m.synchronize do - until in_idle - c.wait(0.1) - end - end - th.raise(Interrupt) - exception_raised = true + th = Thread.start do + Thread.pass until in_idle + Thread.main.raise(Interrupt) end imap.idle do |res| - m.synchronize do - in_idle = true - c.signal - until exception_raised - c.wait(0.1) - end - end + in_idle = true + sleep 1 end rescue Interrupt + ensure + th.kill if th.alive? end assert_equal(2, requests.length) assert_equal("RUBY0001 IDLE\r\n", requests[0]) -- Yusuke Endoh