遠藤です。

2010年5月6日21:50 KOSAKI Motohiro <kosaki.motohiro / gmail.com>:
> というわけで、先の発言は撤回します。考慮が足りなくてすいません。

とんでもないです。ご意見ありがとうございます。


> あと、ちょっと脱線なのですが、使う側から見ると原因を切り分けたいのって二種類ある気がしますね。
> 1) タイムアウトとCV#sinal
> 2) タイムアウトとspurious wakeup
>
> 1は今の議論でpredicateを呼び出し側がチェックするはずだから考慮不要という結論になったと
> 思います。2はどうしましょう?今のインターフェースだとCV#waitの戻り値はselfなので、
> 判定不可能ですよね?

実際に、

- 3 秒ごとに wakeup して定期処理をする
- predicate が真になったらすぐに終わる

という処理を書いて考えてみました (このユースケースが適切かどうかは議論の
余地がある) 。


現状でも

  m.synchronize do
    t = Time.now + 3
    until predicate
      t2 = Time.now
      cv.wait(m, t - t2) if t > t2
      break if predicate
      if Time.now > t
        t += 3
        # 定期処理をする
      end
    end
    # predicate が真になった
  end

とすれば、判定できるような気がします。


CV#wait が ETIMEOUT の時に true を返し、そうでないときに false を返すと
すると

  m.synchronize do
    t = Time.now + 3
    until predicate
      t2 = Time.now
      if t <= t2 || cv.wait(m, t - t2)
        break if predicate
        t += 3
        # 定期処理をする
      end
    end
    # predicate が真になった
  end

と書けると思います。1 行減っただけで、大して変わりません。


もし cv.wait が絶対時刻を受け取る、かつ、与えられた時刻が過去だった場合は
直ちにリターンする、という仕様だった場合は、

  m.synchronize do
    t = Time.now + 3
    until predicate
      if cv.wait(m, t) && !predicate
        t += 3
        # 定期処理をする
      end
    end
    # predicate が真になった
  end

と、だいぶすっきりするような気がします。やはりこれがあるべき姿なのかも。


ただし、どのコードも実際に走らせていませんし、私が気づいてない問題がある
かもしれません。スレッドこわい。

-- 
Yusuke Endoh <mame / tsg.ne.jp>