module Concurrent::Promises::Resolvable

Public Class Methods

atomic_resolution(resolvable_map) click to toggle source

Resolves all passed events and futures to the given resolutions if possible (all are unresolved) or none.

@param [Hash{Resolvable=>resolve_arguments}, Array<Array(Resolvable, resolve_arguments)>] resolvable_map

collection of resolvable events and futures which should be resolved all at once
and what should they be resolved to, examples:
```ruby
{ a_resolvable_future1 => [true, :val, nil],
  a_resolvable_future2 => [false, nil, :err],
  a_resolvable_event => [] }
```
 or
```ruby
[[a_resolvable_future1, [true, :val, nil]],
 [a_resolvable_future2, [false, nil, :err]],
 [a_resolvable_event, []]]
```

@return [true, false] if success

# File lib/concurrent-ruby-edge/concurrent/edge/promises.rb, line 150
def self.atomic_resolution(resolvable_map)
  # atomic_resolution event => [], future => [true, :v, nil]
  sorted = resolvable_map.to_a.sort_by { |resolvable, _| locking_order_by resolvable }

  reserved = 0
  while reserved < sorted.size && sorted[reserved].first.reserve
    reserved += 1
  end

  if reserved == sorted.size
    sorted.each { |resolvable, args| resolvable.resolve(*args, true, true) }
    true
  else
    while reserved > 0
      reserved -= 1
      raise 'has to be reserved' unless sorted[reserved].first.release
    end
    false
  end
end
locking_order_by(resolvable) click to toggle source

@return [Comparable] an item to sort the resolvable events or futures

by to get the right global locking order of resolvable events or futures

@see .atomic_resolution

# File lib/concurrent-ruby-edge/concurrent/edge/promises.rb, line 128
def self.locking_order_by(resolvable)
  resolvable.object_id
end

Public Instance Methods

release() click to toggle source

@return [true, false] on successful release of the reservation

# File lib/concurrent-ruby-edge/concurrent/edge/promises.rb, line 121
def release
  compare_and_set_internal_state(RESERVED, PENDING)
end
reserve() click to toggle source

Reserves the event or future, if reserved others are prevented from resolving it. Advanced feature. Be careful about the order of reservation to avoid deadlocks, the method blocks if the future or event is already reserved until it is released or resolved.

@example

f = Concurrent::Promises.resolvable_future
reserved = f.reserve
Thread.new { f.resolve true, :val, nil } # fails
f.resolve true, :val, nil, true if reserved # must be called only if reserved

@return [true, false] on successful reservation

# File lib/concurrent-ruby-edge/concurrent/edge/promises.rb, line 111
def reserve
  while true
    return true if compare_and_set_internal_state(PENDING, RESERVED)
    return false if resolved?
    # FIXME (pitr-ch 17-Jan-2019): sleep until given up or resolved instead of busy wait
    Thread.pass
  end
end