Created
September 18, 2012 22:40
-
-
Save pettyjamesm/3746457 to your computer and use it in GitHub Desktop.
Ruby Semaphore Implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'monitor' | |
class Semaphore | |
def initialize(maxval = nil) | |
maxval = maxval.to_i unless maxval.nil? | |
raise ArgumentError.new("Semaphores must use a positive maximum value or have no maximum!") if maxval and maxval <= 0 | |
@max = maxval || -1 | |
@count = 0 | |
@mon = Monitor.new | |
@dwait = @mon.new_cond | |
@uwait = @mon.new_cond | |
end | |
def count; @mon.synchronize { @count } end | |
def up!(number = 1) | |
if (number > 1) | |
number.times { up!(1) } | |
count | |
else | |
@mon.synchronize do | |
@uwait.wait while @max > 0 and @count == @max | |
@dwait.signal if @count == 0 | |
@count += 1 | |
end | |
end | |
end | |
def down!(number = 1) | |
if (number > 1) | |
number.times { down!(1) } | |
count | |
else | |
@mon.synchronize do | |
@dwait.wait while @count == 0 | |
@uwait.signal if @count == @max | |
@count -= 1 | |
end | |
end | |
end | |
end |
Thanks a bunch! This works well. In my project I also added the following aliases, which provide the more classical terminology:
alias_method :wait, :down!
alias_method :signal, :up!
Thanks or sharing this gist. I was looking around for something like that.
What kind of code is "@dwait.wait while @count == 0"??!!
@ldcl289 it's been a long time since I wrote this gist, but basically you can't decrement a semaphore lower than 0. Semantically, when that happens the calling thread is supposed to be blocked and go to the wait queue.
An 'if' condition would have sufficed, but a 'while' statement is also valid and protects against modifications to this class that might call @dwait.broadcast (waking up more than the appropriate number of waiters).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On more than one occasion I've been bothered by the fact that there's no standard implementation of semaphores in ruby. Sometimes a semaphore really is a more expressive synchronization metaphor. So- even though this implementation is making a more primitive synchronization object out of more complex ones, I've still found it useful enough to share.