Best way to synchronize access to a method?

All,

I’m reading through the Pickaxe book on synchronization and threading.
I want to have a method that will basically put a MAX() value from a
table and I want to ensure that two threads don’t execute this code at
the same time.

I’m thinking I can just have my object descend from Monitor (< Monitor)
and then put “synchronize” around the relevant code, like so:

class myClass < Monitor

def get_max_value
synchronize { max_value = do_select_to_get_max_value }
max_value
end

This should work just fine - correct?

Thanks,
Wes

Wes G. wrote:

All,

I’m reading through the Pickaxe book on synchronization and threading.
I want to have a method that will basically put a MAX() value from a
table and I want to ensure that two threads don’t execute this code at
the same time.

I’m thinking I can just have my object descend from Monitor (< Monitor)
and then put “synchronize” around the relevant code, like so:

class myClass < Monitor

def get_max_value
synchronize { max_value = do_select_to_get_max_value }
max_value
end

This should work just fine - correct?

Thanks,
Wes

There is an admonition in the Pickaxe book that says “In both the class
form and when including MonitorMixin in an existing class it is
essential to invoke super in the class’s initialize method.”

I want my sychronization to occur in a class method. So that would seem
to obviate the need for the super in the “initialize” block. Am I
correct?

Thanks,
Wes

Wes G. wrote:

Wes G. wrote:

All,

I’m reading through the Pickaxe book on synchronization and threading.
I want to have a method that will basically put a MAX() value from a
table and I want to ensure that two threads don’t execute this code at
the same time.

I’m thinking I can just have my object descend from Monitor (< Monitor)
and then put “synchronize” around the relevant code, like so:

class myClass < Monitor

def get_max_value
synchronize { max_value = do_select_to_get_max_value }
max_value
end

This should work just fine - correct?

Thanks,
Wes

There is an admonition in the Pickaxe book that says “In both the class
form and when including MonitorMixin in an existing class it is
essential to invoke super in the class’s initialize method.”

I want my sychronization to occur in a class method. So that would seem
to obviate the need for the super in the “initialize” block. Am I
correct?

Thanks,
Wes

Yeah, I definitely want the synchronization at the class level - do I
extend the class object directly instead of doing an “include
MonitorMixin”?

Wes

Wes G. wrote:

Thanks,
Thanks,
Wes

You have several problems in your code you may want to look at before
thinking
about Threads:

  • myClass has to be spelled MyClass (see Constants in Ruby)

  • get_max_value isn’t a class method (use self.get_max_value if you want
    such)

  • max_value is only defined inside the block, so you get
    “undefined local variable or method `max_value’ for MyClass:Class”

  • if you define it as class method the interpreter will show you
    “undefined method `synchronize’ for MyClass:Class” because synchronize
    isn’t a class method

  • most of the time when the documentation is saying “it is essential
    to…”
    it is there for a reason

I don’t want to be harsh, but it would be nice to let the interpreter
find
the obvious bugs it is able to find.

maybe that is what you want:

require ‘thread’

class MyClass
@@mutex = Mutex.new

def self.do_select_to_get_max_value;
42
end

def self.get_max_value
@@mutex.synchronize do
return do_select_to_get_max_value
end
end
end

p MyClass::get_max_value

cheers

Simon

Simon Kröger wrote:

Wes G. wrote:

Thanks,
Thanks,
Wes

You have several problems in your code you may want to look at before
thinking
about Threads:

  • myClass has to be spelled MyClass (see Constants in Ruby)

  • get_max_value isn’t a class method (use self.get_max_value if you want
    such)

  • max_value is only defined inside the block, so you get
    “undefined local variable or method `max_value’ for MyClass:Class”

  • if you define it as class method the interpreter will show you
    “undefined method `synchronize’ for MyClass:Class” because synchronize
    isn’t a class method

  • most of the time when the documentation is saying “it is essential
    to…”
    it is there for a reason

I don’t want to be harsh, but it would be nice to let the interpreter
find
the obvious bugs it is able to find.

maybe that is what you want:

require ‘thread’

class MyClass
@@mutex = Mutex.new

def self.do_select_to_get_max_value;
42
end

def self.get_max_value
@@mutex.synchronize do
return do_select_to_get_max_value
end
end
end

p MyClass::get_max_value

cheers

Simon

Simon,

Thanks for the feedback. The code below appears to work. Do you agree
that the code will be sychronized on the class object itself?

=====================

require ‘monitor’

class Job < ActiveRecord::Base
self.extend(MonitorMixin)

public
def self.get_next_job_number
max_value = nil
synchronize {
max_value = self.find(:first, :select => ‘MAX(AbsJobNumber) AS
max’).max
}
max_value.to_i + 1
end
end

I also just realized that I really need to synchronize the select and
subsequent insert so I will probably handle that in another class.

However, I believe this code would work as fas as class synchronization.

Wes

On Tue, 11 Jul 2006, Wes G. wrote:

class myClass < Monitor

def get_max_value
synchronize { max_value = do_select_to_get_max_value }
max_value
end

This should work just fine - correct?

Just a completely un-Ruby related but Threading in general related
observation.

Think in terms of complete transactions.

So you have the max now.

What are you going to do with it?

Remember, by the time you use it, it may well be wrong. So the
synchronization blocked other threads whilst you were calculating the
max value, but as soon as you have the value, myClass is can be modified
by another thread!

So, do you just want it as a rough indicator of what it was at the time
you
said “get_max_value”?

Or do you need it to be exactly and every time the true max value at the
instant you use it?

In which case you have a bug, a thread race. And it doesn’t matter which
language you are programming in!

So there is two approaches to this…

  1. Move the synchronization out to client to synchronize both the
    get_max and the use of it.

  2. Move the get_max and the use into myClass. This conforms better to
    the Law of Demeter or the Tell Don’t Ask principle.

John C. Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : [email protected]
New Zealand

Carter’s Clarification of Murphy’s Law.

“Things only ever go right so that they may go more spectacularly wrong
later.”

From this principle, all of life and physics may be deduced.

John,

Thanks - I realized that a while ago, and I synchronized the use of the
id along with the get, so I believe all is well now.

WG