Class: Farce::Signal
- Inherits:
-
Object
- Object
- Farce::Signal
- Includes:
- Internal::Noncopyable, Farce::Shareable::Unfreezable, Internal::Inspect
- Defined in:
- lib/farce/signal.rb
Overview
A Ractor-shareable notification signal for changes to separately synchronized state. Broadcast after updating the state. Waiters check that state again after each notification. A broadcast wakes all current waiters and advances the signal's generation.
Instance Method Summary collapse
-
#broadcast ⇒ Integer
Advance the generation and wake all current waiters.
-
#generation ⇒ Integer
Read the current generation.
-
#initialize ⇒ Signal
constructor
A new instance of Signal.
-
#num_waiting ⇒ Integer
The number of callers currently waiting.
-
#wait(observed = nil, timeout: nil) { ... } ⇒ Integer, ...
Wait for the generation to change.
-
#wait_until(timeout: nil) { ... } ⇒ BasicObject?
Check a condition immediately, then check again after broadcasts until it succeeds.
-
#wait_while(timeout: nil) { ... } ⇒ true?
Check a condition immediately, then after broadcasts while it remains truthy.
Methods included from Shareable
Methods included from Internal::Noncopyable
Constructor Details
#initialize ⇒ Signal
Returns a new instance of Signal.
26 27 28 29 |
# File 'lib/farce/signal.rb', line 26 def initialize @signal = Internal::Signal.new super end |
Instance Method Details
#broadcast ⇒ Integer
Advance the generation and wake all current waiters.
37 |
# File 'lib/farce/signal.rb', line 37 def broadcast = @signal.broadcast |
#generation ⇒ Integer
Read the current generation. Take this snapshot before checking external state.
33 |
# File 'lib/farce/signal.rb', line 33 def generation = @signal.generation |
#num_waiting ⇒ Integer
Returns the number of callers currently waiting.
40 |
# File 'lib/farce/signal.rb', line 40 def num_waiting = @signal.num_waiting |
#wait(observed = nil, timeout: nil) { ... } ⇒ Integer, ...
Wait for the generation to change. Without a snapshot, wait for the next broadcast. Return immediately if the supplied generation has already changed.
48 |
# File 'lib/farce/signal.rb', line 48 def wait(observed = nil, timeout: nil, &) = @signal.wait(observed, timeout:, &) |
#wait_until(timeout: nil) { ... } ⇒ BasicObject?
Check a condition immediately, then check again after broadcasts until it succeeds. Take a generation snapshot before every check so a broadcast during the check is not missed. The block runs in the caller without holding a signal lock. Synchronize access to shared state inside the block, and claim the resource there if another waiter could consume it.
One timeout budget covers all checks and waits. The block is not interrupted when time expires. A timeout of zero checks once without waiting. Exceptions from the block propagate to the caller.
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/farce/signal.rb', line 76 def wait_until(timeout: nil) raise LocalJumpError, "no block given" unless block_given? Internal.with_timeout(timeout) do |_, deadline| observed = generation result = yield return result if result remaining = deadline - Clock.now if deadline return if remaining && !remaining.positive? return unless wait(observed, timeout: remaining) end end |
#wait_while(timeout: nil) { ... } ⇒ true?
Check a condition immediately, then after broadcasts while it remains truthy. Uses the same timeout budget and notification handling as #wait_until.
57 58 59 60 |
# File 'lib/farce/signal.rb', line 57 def wait_while(timeout: nil) raise LocalJumpError, "no block given" unless block_given? wait_until(timeout:) { !yield } end |