Class: Async::Semaphore
- Inherits:
-
Object
- Object
- Async::Semaphore
- Defined in:
- lib/async/semaphore.rb
Overview
A semaphore is used to control access to a common resource in a concurrent system. A useful way to think of a semaphore as used in the real-world systems is as a record of how many units of a particular resource are available, coupled with operations to adjust that record safely (i.e. to avoid race conditions) as units are required or become free, and, if necessary, wait until a unit of the resource becomes available.
Instance Attribute Summary collapse
-
#count ⇒ Object
readonly
The current number of tasks that have acquired the semaphore.
-
#limit ⇒ Object
readonly
The maximum number of tasks that can acquire the semaphore.
-
#waiting ⇒ Object
readonly
The tasks waiting on this semaphore.
Instance Method Summary collapse
-
#acquire { ... } ⇒ Object
Acquire the semaphore, block if we are at the limit.
-
#async(*arguments, parent: (@parent or Task.current), **options) ⇒ Object
Run an async task.
-
#blocking? ⇒ Boolean
Whether trying to acquire this semaphore would block.
-
#empty? ⇒ Boolean
Is the semaphore currently acquired?.
-
#initialize(limit = 1, parent: nil) ⇒ Semaphore
constructor
A new instance of Semaphore.
-
#release ⇒ Object
Release the semaphore.
Constructor Details
#initialize(limit = 1, parent: nil) ⇒ Semaphore
Returns a new instance of Semaphore.
26 27 28 29 30 31 32 |
# File 'lib/async/semaphore.rb', line 26 def initialize(limit = 1, parent: nil) @count = 0 @limit = limit @waiting = [] @parent = parent end |
Instance Attribute Details
#count ⇒ Object (readonly)
The current number of tasks that have acquired the semaphore.
35 36 37 |
# File 'lib/async/semaphore.rb', line 35 def count @count end |
#limit ⇒ Object (readonly)
The maximum number of tasks that can acquire the semaphore.
38 39 40 |
# File 'lib/async/semaphore.rb', line 38 def limit @limit end |
#waiting ⇒ Object (readonly)
The tasks waiting on this semaphore.
41 42 43 |
# File 'lib/async/semaphore.rb', line 41 def waiting @waiting end |
Instance Method Details
#acquire { ... } ⇒ Object
Acquire the semaphore, block if we are at the limit. If no block is provided, you must call release manually.
72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/async/semaphore.rb', line 72 def acquire wait @count += 1 return unless block_given? begin return yield ensure self.release end end |
#async(*arguments, parent: (@parent or Task.current), **options) ⇒ Object
Run an async task. Will wait until the semaphore is ready until spawning and running the task.
54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/async/semaphore.rb', line 54 def async(*arguments, parent: (@parent or Task.current), **) wait parent.async(**) do |task| @count += 1 begin yield task, *arguments ensure self.release end end end |
#blocking? ⇒ Boolean
Whether trying to acquire this semaphore would block.
49 50 51 |
# File 'lib/async/semaphore.rb', line 49 def blocking? @count >= @limit end |
#empty? ⇒ Boolean
Is the semaphore currently acquired?
44 45 46 |
# File 'lib/async/semaphore.rb', line 44 def empty? @count.zero? end |
#release ⇒ Object
Release the semaphore. Must match up with a corresponding call to acquire
. Will release waiting fibers in FIFO order.
87 88 89 90 91 92 93 94 95 |
# File 'lib/async/semaphore.rb', line 87 def release @count -= 1 while (@limit - @count) > 0 and fiber = @waiting.shift if fiber.alive? fiber.resume end end end |