Forum: Ruby Synchronized object

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.
Kroeger, Simon (ext) (Guest)
on 2006-04-21 18:48
(Received via mailing list)
Dear ruby-talk,

is there a nice, concise way to lock each and
every method against all other methods of an object?

To elaborate: I want to make sure that only one method of
a specific object (not class) can run at a each point in
time regardless of how many threads are using this object.

I would hope there is module i just have to include in
my class definition.

cheers and thanks

Simon
Farrel L. (Guest)
on 2006-04-21 19:22
(Received via mailing list)
You could have a class wide Mutex.

class MyClass
  @@mutex = Mutex.new
  def atomicy_method
    @@mutex.synchronise do
        # Code here
    end
  end
end

Farrel
David P. (Guest)
on 2006-04-21 19:31
(Received via mailing list)
Simon,

Look at the Monitor module.

For example:
require 'monitor'

class Foo
  include MonitorMixin

  def bar
    self.synchronized do
      # stuff
    end
  end

  def baz
    self.synchronized do
      # more stuff
    end
  end
end

It's a little less syntactically sugary than Java, but about the same as
C#.

Do this help?

Thanks,

David
James G. (Guest)
on 2006-04-21 19:34
(Received via mailing list)
On Apr 21, 2006, at 9:47 AM, Kroeger, Simon (ext) wrote:

> my class definition.
You could wrap it in a delegate object you strip of methods, then
just have method_missing() forward the messages inside a synchronize
block.

James Edward G. II
Logan C. (Guest)
on 2006-04-21 19:34
(Received via mailing list)
On Apr 21, 2006, at 10:47 AM, Kroeger, Simon (ext) wrote:

> my class definition.
>
> cheers and thanks
>
> Simon
>

Well it's not quite as easy as Java but:
http://www.ruby-doc.org/stdlib/libdoc/monitor/rdoc...


obj.methods.each do |meth|
    (class << obj; self; end).module_eval <<HERE
       def #{meth}(*args, &block)
           self.synchronize { super }
       end
HERE

end

obj.extend(MonitorMixin)

I did it in that order since I wouldn't want a synchronize
{ synchronize }
Andy G. (Guest)
on 2006-04-21 19:38
(Received via mailing list)
On Fri, Apr 21, 2006 at 11:47:56PM +0900, Kroeger, Simon (ext) wrote:
> definition.
If you want something like you get in Java with the "synchronized"
keyword, that's a monitor, and the standard library includes
(the not terribly well documented) monitor.rb:

http://www.ruby-doc.org/stdlib/libdoc/monitor/rdoc/

(also http://en.wikipedia.org/wiki/Monitor_%28synchronization%29 )

Whether it's nice or concise I don't know - it's certainly not a
"one-liner" way to achieve what you want but it might get you a long
way along the road.  If you use it, I'd personally be interested in
how you got on.

(Caveat: I haven't used this, I just saw "synchronized object" in your
subject line, thought "monitor", and searched the web for "ruby
monitor synchronization" which led me to this info.)

Hope this helps,

-Andy
Simon Kröger (Guest)
on 2006-04-21 23:26
(Received via mailing list)
Logan C. wrote:

>
> end
>
> obj.extend(MonitorMixin)
>
> I did it in that order since I wouldn't want a synchronize { synchronize }

accepted answer ... well kind of. ;)

running your code (with an empty array) gave me:

ruby 1.8.4 (2005-12-24) [i386-mswin32]

(eval):1: warning: redefining `__send__' may cause serious problem
(eval):1: warning: redefining `__id__' may cause serious problem
(eval):2:in `extend': undefined method `synchronize' for
#<Array:0x2816468> (NoMethodError)

but i got the right idea i think. My code now looks like:
---------------------------------------------------------------------
require 'monitor'

def sync obj
  meth = obj.methods - %w{__send__ __id__}
  klass = class << obj.extend(MonitorMixin); self; end
  meth.each{|m|klass.module_eval "def #{m}(*a,&b)synchronize{super}end"}
  obj
end

---------------------------------------------------------------------

usage:
---------------------------------------------------------------------
obj = sync([])
obj.push 'a'
p obj
---------------------------------------------------------------------

and now that i see it, it looks quite simple :)

thanks to all of you who responded

cheers

Simon
David C. (Guest)
on 2006-04-22 04:18
(Received via mailing list)
On Friday 21 April 2006 10:47 am, Kroeger, Simon (ext) wrote:
> Dear ruby-talk,
>
> is there a nice, concise way to lock each and
> every method against all other methods of an object?
>
> To elaborate: I want to make sure that only one method of
> a specific object (not class) can run at a each point in
> time regardless of how many threads are using this object.

> I would hope there is module i just have to include in
> my class definition.
>
> cheers and thanks
>
> Simon

It would be relatively easy to write a class that uses Monitor and
delegates
to specifc object.  Thus, much like Java's Collections.synchronizedFoo,
you
could have

Synchronizer.new(foo) that would synchronize ANY object.

David
Patrick H. (Guest)
on 2006-04-22 06:57
(Received via mailing list)
On 4/21/06, David C. <removed_email_address@domain.invalid> wrote:
> > I would hope there is module i just have to include in
> Synchronizer.new(foo) that would synchronize ANY object.
>
> David
>
>

require 'monitor'

class AutoMonitor
  include MonitorMixin

  def initialize(obj)
    mon_initialize
    @obj = obj
  end

  def method_missing(sym, *args, &block)
    synchronize do
      @obj.send(sym, *args, &block)
    end
  end
end

class Class
  def monitored_new(*args, &block)
    AutoMonitor.new(new(*args, &block))
  end
end


Something like this and then you can:

f = Foo.monitored_new

pth
Simon Kröger (Guest)
on 2006-04-22 16:26
(Received via mailing list)
Thanks a lot, but consider this:

-------------------------------------------------------------------------
require 'monitor'

class AutoMonitor
  include MonitorMixin

  def initialize(obj)
    mon_initialize
    @obj = obj
  end

  def method_missing(sym, *args, &block)
    synchronize do
      @obj.send(sym, *args, &block)
    end
  end
end

def sync obj
  meth = obj.methods - %w{__send__ __id__}
  klass = class << obj.extend(MonitorMixin); self; end
  meth.each{|m|klass.module_eval "def #{m}(*a,&b)synchronize{super}end"}
  obj
end

hash = {"test1" => 1, AutoMonitor.new("test2") => 2, sync('test3') => 3}

p hash.include?("test1") #=> true
p hash.include?(AutoMonitor.new("test1")) #=> false
p hash.include?("test2") #=> false
p hash.include?(AutoMonitor.new("test2")) #=> false

#but

p hash.include?("test1") #=> true
p hash.include?(sync("test1")) #=> true
p hash.include?("test3") #=> true
p hash.include?(sync("test3")) #=> true
-------------------------------------------------------------------------

Of course it is possible to enhance AutoMonitor to handle these cases,
but i like the 4 liner. :)

If only i could make this module_eval go away. (or at least use the
block form)

cheers

Simon
This topic is locked and can not be replied to.