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