Synchronized object

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

You could have a class wide Mutex.

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

Farrel

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

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

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/index.html

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 }

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. :wink:

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: redefiningid’ may cause serious problem
(eval):2:in extend': undefined methodsynchronize’ 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 :slight_smile:

thanks to all of you who responded

cheers

Simon

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

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 Monitor (synchronization) - Wikipedia )

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

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. :slight_smile:

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

cheers

Simon

On 4/21/06, David C. [email protected] 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