module ThreadSafe::Util::CheapLockable

Provides a cheapest possible (mainly in terms of memory usage) Mutex with the ConditionVariable bundled in.

Usage:

class A
  include CheapLockable

  def do_exlusively
    cheap_synchronize { yield }
  end

  def wait_for_something
    cheap_synchronize do
      cheap_wait until resource_available?
      do_something
      cheap_broadcast # wake up others
    end
  end
end

Private Instance Methods

cheap_broadcast() click to toggle source
# File lib/thread_safe/util/cheap_lockable.rb, line 57
def cheap_broadcast
  waiters = @waiters ||= []
  waiters.shift << true until waiters.empty?
  self
end
cheap_synchronize() { || ... } click to toggle source

Making use of the Rubinius' ability to lock via object headers to avoid the overhead of the extra Mutex objects.

# File lib/thread_safe/util/cheap_lockable.rb, line 27
def cheap_synchronize
  Rubinius.lock(self)
  begin
    yield
  ensure
    Rubinius.unlock(self)
  end
end
cheap_wait() click to toggle source
# File lib/thread_safe/util/cheap_lockable.rb, line 36
def cheap_wait
  wchan = Rubinius::Channel.new

  begin
    waiters = @waiters ||= []
    waiters.push wchan
    Rubinius.unlock(self)
    signaled = wchan.receive_timeout nil
  ensure
    Rubinius.lock(self)

    unless signaled or waiters.delete(wchan)
      # we timed out, but got signaled afterwards (e.g. while waiting to
      # acquire @lock), so pass that signal on to the next waiter
      waiters.shift << true unless waiters.empty?
    end
  end

  self
end