Skip to content

Commit 1b21523

Browse files
committed
Backport Semaphore#limit= (#215).
1 parent dc14d1b commit 1b21523

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

lib/async/semaphore.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ def initialize(limit = 1, parent: nil)
4040
# The tasks waiting on this semaphore.
4141
attr :waiting
4242

43+
# Allow setting the limit. This is useful for cases where the semaphore is used to limit the number of concurrent tasks, but the number of tasks is not known in advance or needs to be modified.
44+
#
45+
# On increasing the limit, some tasks may be immediately resumed. On decreasing the limit, some tasks may execute until the count is < than the limit.
46+
#
47+
# @parameter limit [Integer] The new limit.
48+
def limit= limit
49+
difference = limit - @limit
50+
@limit = limit
51+
52+
# We can't suspend
53+
if difference > 0
54+
difference.times do
55+
break unless fiber = @waiting.shift
56+
57+
fiber.resume
58+
end
59+
end
60+
end
61+
4362
# Is the semaphore currently acquired?
4463
def empty?
4564
@count.zero?

spec/async/semaphore_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,43 @@
116116
end
117117
end
118118

119+
context '#limit=' do
120+
it "releases tasks when limit is increased" do
121+
subject.acquire
122+
expect(subject.count).to be == 1
123+
expect(subject.blocking?).to be_truthy
124+
125+
task = Async do
126+
subject.acquire
127+
end
128+
129+
subject.limit = 2
130+
task.wait
131+
132+
expect(subject.count).to be == 2
133+
end
134+
135+
it "blocks tasks when limit is decreased" do
136+
subject.limit = 2
137+
subject.acquire
138+
subject.acquire
139+
140+
expect(subject.count).to be == 2
141+
expect(subject.blocking?).to be_truthy
142+
143+
task = Async do
144+
subject.acquire
145+
end
146+
147+
subject.limit = 1
148+
subject.release
149+
subject.release
150+
task.wait
151+
152+
expect(subject.count).to be == 1
153+
end
154+
end
155+
119156
context '#empty?' do
120157
it 'should be empty unless acquired' do
121158
expect(subject).to be_empty

0 commit comments

Comments
 (0)