Skip to content

Instantly share code, notes, and snippets.

@pettyjamesm
Created September 18, 2012 22:40
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pettyjamesm/3746457 to your computer and use it in GitHub Desktop.
Save pettyjamesm/3746457 to your computer and use it in GitHub Desktop.
Ruby Semaphore Implementation
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
@pettyjamesm
Copy link
Author

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.

@vy-let
Copy link

vy-let commented Jan 2, 2014

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!

@yadavsaroj
Copy link

Thanks or sharing this gist. I was looking around for something like that.

@ldcl289
Copy link

ldcl289 commented Jul 21, 2014

What kind of code is "@dwait.wait while @count == 0"??!!

@pettyjamesm
Copy link
Author

@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