Skip to content

Commit 6ff4711

Browse files
authored
Implement semaphore using linked list. (#203)
1 parent fa81ca9 commit 6ff4711

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

lib/async/semaphore.rb

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# Released under the MIT License.
44
# Copyright, 2018-2022, by Samuel Williams.
55

6+
require_relative 'list'
7+
68
module Async
79
# A synchronization primitive, which limits access to a given resource.
810
# @public Since `stable-v1`.
@@ -12,7 +14,7 @@ class Semaphore
1214
def initialize(limit = 1, parent: nil)
1315
@count = 0
1416
@limit = limit
15-
@waiting = []
17+
@waiting = List.new
1618

1719
@parent = parent
1820
end
@@ -73,26 +75,34 @@ def acquire
7375
def release
7476
@count -= 1
7577

76-
while (@limit - @count) > 0 and fiber = @waiting.shift
77-
if fiber.alive?
78-
Fiber.scheduler.resume(fiber)
79-
end
78+
while (@limit - @count) > 0 and node = @waiting.first
79+
node.resume
8080
end
8181
end
8282

8383
private
8484

85+
class FiberNode < List::Node
86+
def initialize(fiber)
87+
@fiber = fiber
88+
end
89+
90+
def resume
91+
if @fiber.alive?
92+
Fiber.scheduler.resume(@fiber)
93+
end
94+
end
95+
end
96+
97+
private_constant :FiberNode
98+
8599
# Wait until the semaphore becomes available.
86100
def wait
87-
fiber = Fiber.current
101+
return unless blocking?
88102

89-
if blocking?
90-
@waiting << fiber
103+
@waiting.stack(FiberNode.new(Fiber.current)) do
91104
Fiber.scheduler.transfer while blocking?
92105
end
93-
rescue Exception
94-
@waiting.delete(fiber)
95-
raise
96106
end
97107
end
98108
end

0 commit comments

Comments
 (0)