class Variable

Lightweight concurrency variables

These are inspired by Haskells MVar and IVar types.

Constants

EMPTY
TIMEOUT

Public Class Methods

new(condition_variable:, mutex:, value: EMPTY) click to toggle source

Initialize object

@param [Object] value

the initial value

@return [undefined]

# File lib/variable.rb, line 83
def initialize(condition_variable:, mutex:, value: EMPTY)
  @full  = condition_variable.new
  @mutex = mutex.new
  @value = value
end

Public Instance Methods

read() click to toggle source

Read value, block on empty

@return [Object]

the variable value
# File lib/variable.rb, line 122
def read
  synchronize do
    wait_full
    @value
  end
end
take() click to toggle source

Take value, block on empty

@return [Object]

# File lib/variable.rb, line 92
def take
  synchronize do
    wait_full
    perform_take
  end
end
take_timeout(timeout) click to toggle source

Take value, with timeout

@param [Float] Timeout

@return [Result::Timeout]

in case take resulted in a timeout

@return [Result::Value]

in case take resulted in a value
# File lib/variable.rb, line 108
def take_timeout(timeout)
  synchronize do
    if wait_timeout(@full, timeout, &method(:full?))
      Result::Timeout.new
    else
      Result::Value.new(perform_take)
    end
  end
end
try_put(value) click to toggle source

Try put value into the variable, non blocking

@param [Object] value

@return [self]

# File lib/variable.rb, line 134
def try_put(value)
  synchronize do
    perform_put(value) if empty?
  end

  self
end
with() { |value| ... } click to toggle source

Execute block with value, blocking

@yield [Object]

@return [Object]

the blocks return value
# File lib/variable.rb, line 148
def with
  synchronize do
    wait_full
    yield @value
  end
end

Private Instance Methods

empty?() click to toggle source

Test if state is empty

@return [Boolean]

# File lib/variable.rb, line 214
def empty?
  @value.equal?(EMPTY)
end
full?() click to toggle source

Test if state is full

@return [Boolean]

# File lib/variable.rb, line 207
def full?
  !empty?
end
perform_put(value) click to toggle source

Perform the put

@param [Object] value

# File lib/variable.rb, line 160
def perform_put(value)
  (@value = value).tap { @full.signal }
end
synchronize(&block) click to toggle source

Execute block under mutex

@return [self]

# File lib/variable.rb, line 167
def synchronize(&block)
  @mutex.synchronize(&block)
end
wait(event) { || ... } click to toggle source

Wait for block predicate

@param [ConditionVariable] event

@return [undefined]

# File lib/variable.rb, line 176
def wait(event)
  event.wait(@mutex) until yield
end
wait_full() click to toggle source

Wait till mvar is full

@return [undefined]

# File lib/variable.rb, line 200
def wait_full
  wait(@full, &method(:full?))
end
wait_timeout(event, timeout) { || ... } click to toggle source

Wait with timeout for block predicate

@param [ConditionVariable] event

@return [Boolean]

if wait was terminated due a timeout

@return [undefined]

otherwise
# File lib/variable.rb, line 189
def wait_timeout(event, timeout)
  loop do
    break true if timeout <= 0
    break if yield
    timeout -= Timer.elapsed { event.wait(@mutex, timeout) }
  end
end