# # module SpinLock # class Mutex # def initialize # def lock # def unlock # def try_lock # def exclusive # def exclusive_unlock # class ConditionVariable # def initialize # def wait(mutex) # def signal # def broadcast # end # end of module SpinLock # # $Id: spinlock.rb,v 1.10 2003/03/07 17:37:10 fukumoto Exp $ # if not defined? Thread.exclusive # copied from thread.rb def Thread.exclusive _old = Thread.critical begin Thread.critical = true return yield ensure Thread.critical = _old end end end module SpinLock class Mutex def initialize @locked = false end def lock begin Thread.critical = true while @locked Thread.critical = false Thread.pass Thread.critical = true end @locked = true self ensure Thread.critical = false end end def unlock @locked = false self end def try_lock begin result = false Thread.critical = true unless @locked result = true @locked = true end result ensure Thread.critical = false end end def exclusive begin lock yield # returns with the result of yield ensure unlock end end alias synchronize exclusive alias serialize exclusive def exclusive_unlock # intended to be called from ConditionVariable raise unless @locked # ??? Thread.exclusive do @locked = false yield end end end # # ConditionVariable copied from thread.rb # class ConditionVariable def initialize @waiters = [] end def wait(mutex) mutex.exclusive_unlock do @waiters.push(Thread.current) Thread.stop end mutex.lock end def signal begin t = @waiters.shift t.wakeup if t # changed from t.run rescue ThreadError retry end end def broadcast waiters0 = nil Thread.exclusive do waiters0 = @waiters.dup @waiters.clear end for t in waiters0 begin t.wakeup # changed from t.run rescue ThreadError end end end end end # end of module SpinLock if $0 == __FILE__ require 'benchmark' require 'thread' require 'monitor' require 'threadutil' s = SpinLock::Mutex.new mutex = Mutex.new mon = Monitor.new m = 20 n = 1000 a = 0 Benchmark::bm do |x| x.report { m.threads do n.times do Thread.critical = true; a+=1; Thread.critical = false end end.join; puts a } x.report { m.threads do n.times do s.lock; a+=1; s.unlock end end.join; puts a } x.report { m.threads do n.times do mutex.lock; a+=1; mutex.unlock end end.join; puts a } x.report { m.threads do n.times do mon.enter; a+=1; mon.exit end end.join; puts a } end end