Forum: Ruby Thread synchronization: Mutex or Monitor??

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
2f50086fbb09894a6f94207731130d6c?d=identicon&s=25 unknown (Guest)
on 2005-12-26 15:06
(Received via mailing list)
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?

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.

Any opinions are highly appreciated.

Thanks,
--Leo--
Bf6862e2a409078e13a3979c00bba1d6?d=identicon&s=25 Gregory Seidman (Guest)
on 2005-12-26 15:42
(Received via mailing list)
On Mon, Dec 26, 2005 at 11:05:25PM +0900, 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?
}
} 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.
}
} Any opinions are highly appreciated.

There are at least three (maybe only three -- it's been a long time
since
my operating systems course in college) equivalently powerful
concurrency
control primitives: mutexes, monitors, and semaphores. They are
equivalently powerful because you can implement any one of them in terms
of
any other. The implication, then, is that you should use the primitive
that
best suits your application. Here is some guidance on where each applies
well:

1) Semaphores involve counting, so they are typically used for
controlling
   access to a limited, but plural, number of connections to some
resource.
   Some good examples are audio channels or IO channels.

2) Monitors are an OO construct and work well with controlling
concurrent
   access to the multiple entry points in an object. A good example
might
   be a shared queue object, on which the enqueue and dequeue operations
   are protected.

3) Mutexes are the simplest primitives. They are best for protecting
either
   a single entry point (i.e. a single function/method/block) or global
   data. An example might be a thread-safe printf function that prevents
   interleaved printing.

} Thanks,
} --Leo--
--Greg
2f50086fbb09894a6f94207731130d6c?d=identicon&s=25 unknown (Guest)
on 2005-12-26 17:25
(Received via mailing list)
Gregory,
many thanks for your reply and insightful description of general
concepts of semaphores, mutexes and monitors. As far as I understand,
Ruby implementation of  monitor and mutex provide identical
functionality that in your classification would be combination of your
items 2) and 3).
Ruby Mutex is  quite advanced, pure OO and even can be mixed into any
object (require "mutex_m.rb") exactly the same way as Ruby Monitor.
So, in terms of their functionality and usage they can do the same
things with the same API. Mutex#synchronize allows for control of
multiple access points the same way as Mutex#synchronize does.

--Leo--
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2005-12-26 17:28
(Received via mailing list)
From: "Gregory Seidman" <gsslist+ruby@anthropohedron.net>
>   access to a limited, but plural, number of connections to some resource.
>   interleaved printing.
Also, Critical Sections.

In Ruby,

  Thread.exclusive do
    # No other ruby threads will be scheduled while we're in this
    # Critical Section.  (With a few exceptions, such as if we were
    # to sleep().)
  end


Regards,

Bill
E6dd9cedee99f9d02e5f87d80ee0e681?d=identicon&s=25 Warren Seltzer (Guest)
on 2005-12-27 00:15
(Received via mailing list)
Reading about Forwardable I was shocked to see strange symbol-looking
notations I'd never
seen before.  Nothing the pickaxe led me to believe that :[] or
:@variable was valid Ruby.
I've since figured out, I think, what it must mean but I'm wondering:
What other crazy
syntax am I going to have to figure out?  And does :[] simply name a
function, as I think?

Will I be seeing :&, :**, :) and so on?  Or even :-)  ?

Shocked, simply shocked...

Warren Seltzer
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2005-12-27 00:30
(Received via mailing list)
On Dec 26, 2005, at 5:12 PM, Warren Seltzer wrote:

>
> Shocked, simply shocked...

Symbols are really just immutable Strings.  Not too much magic
there.  By convention, we generally use them to refer to method names
and the like inside our programs (i.e. :each instead of "each").
That's just because they are easier to type, faster in performance,
and we won't need all of String's helper methods for them.

Hope that helps explain what you are seeing.

James Edward Gray II
Fe9b2d0628c0943af374b2fe5b320a82?d=identicon&s=25 Eero Saynatkari (rue)
on 2005-12-27 00:31
Warren Seltzer wrote:
> Reading about Forwardable I was shocked to see strange symbol-looking
> notations I'd never
> seen before.  Nothing the pickaxe led me to believe that :[] or
> :@variable was valid Ruby.
> I've since figured out, I think, what it must mean but I'm wondering:
> What other crazy
> syntax am I going to have to figure out?  And does :[] simply name a
> function, as I think?

:<something> just indicates the variable being a Symbol,
just like the quotes in 'something' indicates that variable
to be a String. A Symbol does not intrinsically refer to a
method, it is just a name (you could just as well use a String):

  foo.send :foobar_method   # is equivalent to
  foo.send 'foobar_method'

So, conceptually, :[] is more or less the same as '[]'
and it may, indeed, be good to think of a Symbol as a
kind of an immutable String :)

> Will I be seeing :&, :**, :) and so on?  Or even :-)  ?

Well, (:-) is valid as the minus operator..

> Shocked, simply shocked...

Ha! Wait until you start constructing Symbols using the
implicit String conversion:

  :'This is a Symbol too'

> Warren Seltzer


E
5befe95e6648daec3dd5728cd36602d0?d=identicon&s=25 Robert Klemme (Guest)
on 2005-12-27 11:55
(Received via mailing list)
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
2f50086fbb09894a6f94207731130d6c?d=identicon&s=25 unknown (Guest)
on 2005-12-27 13:14
(Received via mailing list)
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--
4feed660d3728526797edeb4f0467384?d=identicon&s=25 Bill Kelly (Guest)
on 2005-12-27 20:36
(Received via mailing list)
From: "Robert Klemme" <bob.news@gmx.net>
> - 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.

Agreed, with regard to multiprocessor environments.  With ruby's
current implementation, using Thread.exclusive _where appropriate_
seems perfectly reasonable to me.  Grep ruby's standard library,
you'll see several instances of its use.

For instance drb/drb.rb DRbServer#initialize does the following:

  Thread.exclusive do
    DRb.primary_server = self unless DRb.primary_server
  end

Yes, that could have been done with a Mutex, but why?  Calling
Mutex#synchronize (which in turn calls Mutex#lock and Mutex#unlock)
involves considerably more code executed inside Thread.critical blocks
than that one-liner above.

So if the argument is that Thread.critical is prohibitively costly,
one had better bear that in mind when calling any methods on Mutex.

In the current implementation, each call to Mutex#synchronize
involves around ten or so lines of ruby executed in at least
two separate Thread.critical blocks (one of which is in a loop.)

I agree that the relative costs of all these operations may change
when we get to YARV + native threads + fine-grained locking that
allows multiple ruby threads simultaneously executing on multiple
processors.  I wouldn't be surprised if Ruby's current thread.rb
implementation had to be rewritten for that new system.

But in any case, with ruby's current green threads, Thread.exclusive
is about as efficient as you can get, for simple cases like the
DRb one shown above.  All it does is extend the current thread's
quantum, effectively, for a brief period of time.  There's no
waiting involved.


Regards,

Bill
5befe95e6648daec3dd5728cd36602d0?d=identicon&s=25 Robert Klemme (Guest)
on 2005-12-27 22:40
(Received via mailing list)
Bill Kelly <billk@cts.com> wrote:
>>
>
>
> processors.  I wouldn't be surprised if Ruby's current thread.rb
> implementation had to be rewritten for that new system.

I expect exactly that to happen - even more so, these classes are likely
candidates for an implementation in the runtime system (similarly to
Java's
approach).

> But in any case, with ruby's current green threads, Thread.exclusive
> is about as efficient as you can get, for simple cases like the
> DRb one shown above.  All it does is extend the current thread's
> quantum, effectively, for a brief period of time.  There's no
> waiting involved.

I still don't like this approach even if the std lib does it.  In an
application you'll usually want more fine grained locks than process
wide
locks.  IMHO it's not only a question of efficiency but also of design.
I
prefer to start with the cleaner design and only change to
Thread.exclusive
if there is a real need for this.  I guess you know the quote about
premature optimization...  Of course you can view the usage of several
lower
grained locks vs. Thread.exclusive as an optimization, too (increases
throughput). :-))

Although we differ on this one I guess we've given good arguments for
both
approaches so people can pick whatever they feel more comfortable with.

Kind regards

    robert


PS: Since I do Java for a living it's MT approach might have influenced
me,
there's simply no such thing as an application wide thread exclusive
execution.
This topic is locked and can not be replied to.