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
>
>
>