class QuackConcurrency::SafeSleeper

A {SafeSleeper} can be used to safely sleep a thread or preemptively wake it.

Unlike simply calling +Thread#sleep+, {#sleep} will ensure that only calling {#wake} on this {SafeSleeper} will wake the thread. Any call to +Thread#run+ directly, will be ignored. Threads are still be resumed if +Thread#raise+ is called which may cause problems so it should never be used. A thread can only be put to sleep and woken once for each {SafeSleeper}.

Public Class Methods

new() click to toggle source

Creates a new {SafeSleeper} concurrency tool. @return [SafeSleeper]

Calls superclass method
# File lib/quack_concurrency/safe_sleeper.rb, line 15
def initialize
  super
  @state = :initial
end

Public Instance Methods

sleep(timeout = nil) click to toggle source

@see SafeSleeper#sleep

# File lib/quack_concurrency/safe_sleeper.rb, line 21
def sleep(timeout = nil)
  timer do |start_time|
    deadline = wake_deadline(start_time, timeout)
    enforce_sleep_call_limit
    @mutex.synchronize do
      break if @state == :complete
      @state == :sleep
      wait(deadline)
    ensure
      @state = :complete
    end
  end
end
wake() click to toggle source

@see SafeSleeper#wake

# File lib/quack_concurrency/safe_sleeper.rb, line 36
def wake
  @mutex.synchronize do
    enforce_wake_call_limit
    @state = :complete
    @condition_variable.signal
  end
  nil
end

Private Instance Methods

wait(deadline) click to toggle source

Put this thread to sleep and wait for it to be woken. Will wake if {#wake} is called. If called with a deadline it will wake when deadline is reached. @api private @param deadline [nil,Time] maximum time to sleep, nil for forever @raise [Exception] any exception raised by +ConditionVariable#wait+ (eg. interrupts, ThreadError) @return [void]

# File lib/quack_concurrency/safe_sleeper.rb, line 54
def wait(deadline)
  loop do
    if deadline
      remaining = deadline - Time.now
      @condition_variable.wait(@mutex, remaining) if remaining > 0
    else
      @condition_variable.wait(@mutex)
    end
    break if @state == :complete
    break if deadline && Time.now >= deadline
  end
end
wake_deadline(start_time, timeout) click to toggle source

Calculate the desired time to wake up. @api private @param start_time [nil,Time] time when the thread is put to sleep @param timeout [Numeric] desired time to sleep in seconds, nil for forever @raise [TypeError] if start_time is not nil or a Numeric @raise [ArgumentError] if start_time is negative @return [Time]

# File lib/quack_concurrency/safe_sleeper.rb, line 74
def wake_deadline(start_time, timeout)
  timeout = process_timeout(timeout)
  deadline = start_time + timeout if timeout
end