Synchronized object


#1

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


#2

You could have a class wide Mutex.

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

Farrel


#3

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


#4

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


#5

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 }


#6

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


#7

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


#8

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_(synchronization) )

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


#9

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


#10

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