Skip to content

Commit

Permalink
Merge pull request #5 from robdavid/feature/blocking-wait-group
Browse files Browse the repository at this point in the history
Reduce CPU usage of wait group by blocking. Thanks to @robdavid
  • Loading branch information
naqvis authored Jun 19, 2021
2 parents c0d2b15 + 8152adf commit 5ab1fe0
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 6 deletions.
50 changes: 50 additions & 0 deletions spec/wait_group_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require "./spec_helper"

module XMPP
describe WaitGroup do

it "Should not block on creation" do
wg = WaitGroup.new
wg.wait
end

it "Should block whilst not done" do
wg = WaitGroup.new
wg.add.should eq 1
progress = Atomic(Int32).new(0)
spawn { progress.add(1); wg.wait; progress.add(1) }
sleep 5.milliseconds
# Should get to wait but not beyond it
progress.get.should eq 1
wg.done.should eq 0
while progress.get != 2
sleep 1.milliseconds
end
end

it "Should support multiple waiters" do
wg = WaitGroup.new
wg.add.should eq 1
unblocked = Atomic(Int32).new(0)
nwaiters = 10
(1..nwaiters).each { spawn { wg.wait; unblocked.add(1) } }
sleep 5.milliseconds
unblocked.get.should eq 0
wg.done.should eq 0
while unblocked.get != nwaiters
sleep 1.milliseconds
end
end

it "Won't block again after done" do
wg = WaitGroup.new
wg.add
wg.done
wg.done?.should be_true
wg.wait
wg.add
wg.done?.should be_true
end

end
end
22 changes: 16 additions & 6 deletions src/xmpp/event_manager.cr
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,32 @@ module XMPP
private class WaitGroup
def initialize
@count = Atomic(Int32).new(0)
@span = Time::Span.new(nanoseconds: 5000)
@chan = Channel(Nil).new
end

def add(n = 1)
@count.add n
return @count.get if n == 0
count = @count.add(n) + n # New value
@chan.close if count <= 0
count
end

def count
@count.get
end

def done
add(-1)
end

def done?
@chan.closed?
end

def wait
loop do
return if @count.get == 0
sleep(@span)
end
return if @count.get == 0 # Don't block when first constructed
@chan.receive
rescue Channel::ClosedError
end
end
end

0 comments on commit 5ab1fe0

Please sign in to comment.