Issue #7086 has been updated by rklemme (Robert Klemme).


kosaki (Motohiro KOSAKI) wrote:
> I think Java API spec is crazy and buggy.

:-)

> And then, no timeout doesn't mean the condition become true and an API user always have to ignore the return value and check
> his own condition again.

There is some truth in what you write.  In the usual case you certainly need to check your condition.  But I think nevertheless that the Java way is not crazy.

> Moreover, we have one another mess. When cv#signal was not only fired but also timeout occur, some OS return timeout occur and
> other return cv#signal received. Both POSIX and Java permit such platform dependency. then, you must not trust the return value.

I disagree that the named facts make the return value useless.  See below.

> I'm hesitate to implement it because it seems bring a lot of trouble than worth.

We certainly need to give a bit more thought to this.  So, the condition needs to be checked to be sure it is met.  But: in case of timeout you can do a quick exit of the loop if #wait has a proper return value.  The usage pattern would look like this:

def do_whatever(timeout)
  target = Time.now + timeout

  lock.synchronize do
    until condition
      cv.wait(target - Time.now) or return :fail
    end

    whatever
  end

  :ok
end

The race condition between spurious wakeup, timeout and signaling is really irrelevant.  The reason is this: if any two of them happen at approximately the same time it doesn't matter whether one of them is a few microseconds earlier or the implementation prefers one of them.  The outcome (i.e. return value) is random for the observer anyway.  You also cannot create a test which would verify certain behavior reliably because you cannot control execution order down to the nanosecond.

But: if the timeout is detected it is extremely useful to indicate that fact via the return value.  Otherwise the idiom shown above would become more complex:

def do_whatever(timeout)
  target = Time.now + timeout

  lock.synchronize do
    until condition
      sec = target - Time.now
      return :fail if sec <= 0
      cv.wait sec
    end

    whatever
  end

  :ok
end

If we allow instances of Time and DateTime as "timeout" argument to #wait things become even simpler:

def do_whatever(timeout)
  target = Time.now + timeout

  lock.synchronize do
    until condition
      cv.wait target or return :fail
    end

    whatever
  end

  :ok
end

It would also be nice if MonitorMixin::ConditionVariable allowed for a timeout argument to #wait_until and #wait_while.  Then we could remove the loop altogether yet retain the time limitation.  :-)
----------------------------------------
Bug #7086: ConditionVariable#wait has meaningless return value
https://bugs.ruby-lang.org/issues/7086#change-29798

Author: rklemme (Robert Klemme)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: 
ruby -v: ruby 1.9.3p194 (2012-04-20) [i686-linux]


I consider this an API bug: when invoked with a timeout value the caller cannot distinguish from the return value whether the condition has been signaled or the time has run out.  Consider how Java does it: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html#await(long,%20java.util.concurrent.TimeUnit) and http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html#awaitUntil(java.util.Date)

There's another issue exhibited through the script but I will create a separate ticket for this.


-- 
http://bugs.ruby-lang.org/