Projects

Ticket #572 (new defect)

Opened 2 years ago

Last modified 14 months ago

ConditionVariable#wait should accept a timeout argument

Reported by: honglilai@… Owned by: lsansonetti@…
Priority: blocker Milestone: MacRuby Later
Component: MacRuby Keywords:
Cc:

Description

Right now, ConditionVariable#wait waits forever until the condition is signaled. There should be a way to wait on a condition variable for a bounded time. A typical use case is as follows:

There is a background thread which performs some cleaning function every x seconds. We also want to be able to tell the thread to clean now, or to exit (i.e. quitting its main loop so that we can join the thread). This thread waits on a condition variable for x seconds, and then checks whether there was a timeout on the wait, or whether the wait as signaled. In case of the former it will run the cleanup code. In case of the latter it'll check whether @quit is set, and then either stop the loop or run the cleanup code.

This support for bounded waiting should be implemented by supporting an extra 'timeout' argument in ConditionVariable#wait. In fact JRuby and MRI 1.9.2dev already support it, though differenly. The call seqs are as follows:

MRI <= 1.9.1: ConditionVariable#wait(mutex)
   No native support for bounded time waiting. In Phusion Passenger
   we emulate this with timeout.rb which is very hacky, though it
   seems to work.

MRI 1.9.2dev: ConditionVariable#wait(mutex, timeout)   => integer
   Waits for at most 'timeout' time. 'timeout' may be a floating
   point number.
   Returns the number of *seconds* spent waiting. So even if it
   actually spent 3.5 seconds waiting, it'll either return 3 or 4.
   There is no way to check whether the wait was signaled or
   timed out, you have to guess based on the time waited.

JRuby: ConditionVariable#wait(mutex, timeout)   => boolean
   Waits for at most 'timeout' time. 'timeout' may be a floating
   point number.
   Returns true if condition was signaled, false if it timed out.

I think the JRuby approach makes most sense. We should also convince the MRI developers to change the behavior to match JRuby's before 1.9.2 is released.

Bounded wait can be implemented with pthread_cond_timedwait.

Change History

Changed 2 years ago by lsansonetti@…

Let's see what the ruby-core folks will respond, but I agree that the jruby approach makes more sense. In any case, we should remove ConditionVariable from thread.rb and rewrite it as a wrapper to pthread_cond_t.

Changed 14 months ago by isaackearse@…

Looks like ruby-core have rejected this change a month ago. Below are the reasons given, for more info see the thread on rubymine:  http://redmine.ruby-lang.org/issues/show/2629

Hi, Hongli

Even if there is no return value, you can detect the timeout *without guessing* by the following:

  mutex.synchronize do
    t = Time.now + x
    until @quit
      t2 = Time.now
      cv.wait(mutex, t - t2) if t > t2
      break if @quit
      if Time.now > t
        t += x
        # cleanup code
      end
    end
    # stop the loop
  end

I recommend this code because it is robust against spurious wakeup.

I think the feature you requested can be used to make the code more efficient, like the following:

  mutex.synchronize do
    t = Time.now + x
    until @quit
      t2 = Time.now
      timeout = t <= t2 || cv.wait(mutex, t - t2)
      break if @quit  # (A)
      if timeout
        t += x
        # cleanup code
      end
    end
    # stop the loop
  end

But, the feature is not mandatory, and is even prone to misuse (the check (A) is very easy to forget).

In addition, Tanaka Akira, who has added the timeout feature to CV#wait, rejected the feature.

Consequently, I close this ticket. Sorry for decision against your exception, and also sorry for not deciding sooner.

-- Yusuke Endoh <mame@…>

Changed 14 months ago by lsansonetti@…

  • milestone set to MacRuby Later

Thanks for checking. Let's move the ticket to Later.

Note: See TracTickets for help on using tickets.