From: slonik.az@... Date: 2005-12-27T21:13:25+09:00 Subject: Re: Thread synchronization: Mutex or Monitor?? 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 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 > => # @mon_waiting_queue=[], @mon_owner=nil> > >> m.synchronize { m.synchronize { puts "foo" } } > foo > => nil > >> m=Mutex.new > => # > >> 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 > > >