Robert, thanks a lot for pointing out that Ruby Mutex is _not_ reentrant while Monitor is reentrant. Unfortunately, Ruby documentation (neither Rdoc nor PickAxe book) does not mention this important difference. Best Regards, --Leo-- On 12/27/05, Robert Klemme <bob.news / gmx.net> wrote: > slonik.az / gmail.com wrote: > > Hi Rubyists!! > > Ruby contains two seemingly equivalents tools for thread > > synchronization: Mutex (defined in thread.rb) and Monitor (defined in > > monitor.rb). They both implement classic mutex and conditional > > variable functionality > > and have the same API. This begs two questions: > > > > 1: What is the difference between Monitor and Mutex? > > The main difference is that Monitors are reentrant while Mutexes are not: > > >> require 'monitor' > => true > >> require 'thread' > => true > >> m=Monitor.new > => #<Monitor:0x101a6930 @mon_entering_queue=[], @mon_count=0, > @mon_waiting_queue=[], @mon_owner=nil> > >> m.synchronize { m.synchronize { puts "foo" } } > foo > => nil > >> m=Mutex.new > => #<Mutex:0x10198f80 @locked=false, @waiting=[]> > >> m.synchronize { m.synchronize { puts "foo" } } > ThreadError: stopping only thread > note: use sleep to stop forever > from /usr/lib/ruby/1.8/thread.rb:100:in `stop' > from /usr/lib/ruby/1.8/thread.rb:100:in `lock' > from /usr/lib/ruby/1.8/thread.rb:133:in `synchronize' > from (irb):6 > from /usr/lib/ruby/1.8/thread.rb:135:in `synchronize' > from (irb):6 > from :0 > > > 2: Which one of the two is the preferred solution? PickAxe 1-st > > edition covered Mutex, PickAxe 2-nd edition covers Monitor in main > > text and Mutex in passing in library reference. > > They are mostly equivalent. I guess it mainly boils down to this: if your > code needs to be reentrant or if methods invoke each other that are > synchronized on the same lock use Monitor. For all other cases or where > performance is important use Mutex. (Disclaimer: I didn't benchmark the two > but since the implementation of a reentrant lock is more complicated I guess > Monitor has some overhead over Mutex.) Note also that there is MonitorMixin > which basically allows do to something like > > class Foo > include MonitorMixin > > def do_it_safely() > synchronize { puts "thread safe code" } > end > end > > instead of > > class Foo > def initialize() @lock = Mutex.new end > > def do_it_safely() > @lock.synchronize { puts "thread safe code" } > end > end > > There are more thread control primitives which might help you depending on > the problem you are trying to solve: ConditionVariable and Queue. I > recommend to *not* use Thread.critical and Thread.exclusive (which uses > #critical internally) for several reasons: > > - they limit concurrency more than necessary there is only a single lock > which will prevent all but one thread from executing > > - I view them as quite low level functionality which is purely there to > implement other synchronization features like Mutex, Monitor etc. > > - Although they might not be deprecated when we have a Ruby version that > supports native threads the effect of using this single process wide lock > will be even more dramatic, because there will be even more unused resources > when the lock is held - especially in multiprocessor environments. > > Kind regards > > robert > > >