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. :-)