Reasonable practice?

It the following reasonable? How thread safe is it?

class X
attr :type

def initialize(ary)
 @ary = ary
end

def go
  @ary.each { |x|
    @type = x
    run
  }
end

def run
  puts type
end

end

X.new([‘a’, ‘b’, ‘c’]).go

Is changing the instance variable through each iteration a bad idea?
Of course I could pass the type to #run as an argument, but I’m
experimenting with the concept of “service points” and was wondering
if type could safely be one in this case. My alternative to keep type
as a serve point is to create a Runner class that took type as its
initialize argument, but that seems code heavy.

Thanks,
T.

Trans wrote:

It the following reasonable? How thread safe is it?

class X
attr :type

def initialize(ary)
 @ary = ary
end

def go
  @ary.each { |x|
    @type = x
    run
  }
end

def run
  puts type
end

end

X.new([‘a’, ‘b’, ‘c’]).go

Is changing the instance variable through each iteration a bad idea?
Of course I could pass the type to #run as an argument, but I’m
experimenting with the concept of “service points” and was wondering
if type could safely be one in this case. My alternative to keep type
as a serve point is to create a Runner class that took type as its
initialize argument, but that seems code heavy.

Thanks,
T.

If you just want to print out all of the members of an array, it looks
fine to me. Although maybe you could just substitute the ‘run’ for ‘puts
x’. It means about 4 less lines and one or two less variables. Unless
you plan to use that ‘type’ variable another time. But thats just me, i
dont always like creating one-use methods, especially such small ones.

On 6/15/07, Trans [email protected] wrote:

  @ary.each { |x|
    @type = x

-------------------------> Problem, Thread 1 gets interrupted by Thread2
-------------------------> Thread2 changes @type

X.new([‘a’, ‘b’, ‘c’]).go

Tom I do not know how big the chance is that the scenario above will
happen but it is not thread safe.

I just recently was awoken by Robert K. about instance variable
issues,
so I am not an expert.
Could you come up with passing local variables around as params. The
method calls might become ugly :frowning: or your methods longer :((.

In the simplfied code it will work out nicely but how will it scale to
your real application.

I am working on closure properties right now – they will not solve
your problem yet, but I was thinking a lot about lockable properties,
this will look like this

require ‘labrador/properties’
class X
extend Properties
property :type, :lockable

def go …

  lock_property :type, :lock_type => :write_lock
  self.type = x
  run

ensure
unlock_property :type

but my mileage on this will be bad (1) as I am not a Thread guru and I
do not want to reinvent the wheel, but I am thinking about the
BusyFlag class from Java Threads.

BTW if you look for performance just forget it, I expect a performance
penalty of factor 5 :frowning: for closure based properties.

Cheers
Robert

(1) and non lockable properties are not ready yet :frowning:

On Jun 15, 12:07 am, Aatch R. [email protected] wrote:

If you just want to print out all of the members of an array, it looks
fine to me. Although maybe you could just substitute the ‘run’ for ‘puts
x’. It means about 4 less lines and one or two less variables. Unless
you plan to use that ‘type’ variable another time. But thats just me, i
dont always like creating one-use methods, especially such small ones.

My example is a drastic simplification of what I’m actually doing. My
concern is just with the practice of repeatedly changing an instance
var. I’ve just never used an instance var in this way before, and
worry I might be over looking something --especially thread issues.

I used to write gigantic methods. Over the years I have learned that
smaller is better. I’m getting to the point now that a method with
more than nine lines is rare. You might want to give it some further
consideration.

Thanks,
T.

On 6/15/07, Robert D. [email protected] wrote:

end

def run
 # maybe some work is being done here too?

---------------------------> Threads can also interrupt here and change
@type

  puts type
end

Robert’s right, and I added another place threads might step on
eachother. Since this is a simplification, if you’re calling #type
more than once in the #run method, you might even get different values
within the #run method! Like this:

def run
puts type # => String
--------> another thread calls #go or does something otherwise to change
@type
puts type # => might be a different value now!
puts type # => might be the 3rd different value returned by #type
end

I don’t know anything about lockable properties (haven’t heard of
them), but I think the best way to make your code thread safe is to
only using locally scoped variables. Constants, instance, class,
global, etc variables will probably all require some sort of mechanism
to control access (mutex, semaphore, condition var, etc) if they’re
values are being changed. Those mechanisms typically erode the
performance advantage of parallelizing your program because they spend
time checking if it’s safe to change some variable, and spend time
waiting for a lock to open and whatnot. But when you need to use them
they are handy tools.

You’ll probably have to deal with writing instance variables
somewhere, like #initialize but that doesn’t typically cause thread
safety issues because it’s only ever called once on an object. If you
only ever read those instance variables, you’ll be mostly in the
clear. When you start changing the state of the object you have to be
careful.

In your example, you could remove the line @type = x; and change the
next line to: run(x). Then redefine #run accordingly. You’ll notice
your example code doesn’t really need to change the object’s state to
get the job done, so just write it in a way that doesn’t do that and
you’ll be thread safe. You may or may not be able to apply that idea
to your actual non-example code though.

Regards,
Erwin

On Jun 15, 11:02 pm, “Erwin A.” [email protected] wrote:

end

eachother. Since this is a simplification, if you’re calling #type
I don’t know anything about lockable properties (haven’t heard of
You’ll probably have to deal with writing instance variables
you’ll be thread safe. You may or may not be able to apply that idea
to your actual non-example code though.

Thanks Erwin, that helps. I was toying with not having any methd
arguments. It’s interesting, in that it can be done. However, in a
case like the above it requires intantiaing a new object for dealing
with type.

class X
attr :type

def initialize(ary)
 @ary = ary
end


def go
  @ary.each { |x|
    TypeRunner.new(x).run
  }
end

end

class TypeRunner
attr :type
def initialize(type)
@type = type
end

 def run
   puts type
 end

end

X.new([‘a’, ‘b’, ‘c’]).go

Am I right about this being thread safe® where the first version was
not?

Also, I was thinking. If it’s thread safe to just pass type as an
argument, one would think there could be a way to define a “locked”
instance var that is essentially the same thing but without all the
overhead.

T.

I made a big mistake in that code. Instead of each instance of DooWop
having its own set of locks, every instance would share one set.
Calling a setter in one DooWop object could block a getter/setter in a
totally separate DooWop object. But I think you get the idea, and
maybe agree it’s not really worth the (small) effort to fix it.

Regards,
Erwin

On 6/16/07, Trans [email protected] wrote:

  }

not?
Yes, this is thread safe… each thread that calls #go gets its own
set of objects (TypeRunners) that are separate from the objects in the
other threads.

Also, I was thinking. If it’s thread safe to just pass type as an
argument, one would think there could be a way to define a “locked”
instance var that is essentially the same thing but without all the
overhead.

It seems like it should be simple, but there’s a lot of complexity
when programming multithreaded code. In your example you’re not
changing the state of anything, so that’s why you can simplify
things… but things get out of hand fast. See my comments past the
end of the code below.

Here’s my attempt at a very simple way to do what you’re talking
about… I had trouble getting the methods put in the right namespace,
so maybe my module code isn’t the most elegant but it does what I want
it to do.

require ‘thread’

module Locker
def self.included mod
(class << mod; self; end).instance_eval do

  define_method(:attr_locked) do |*names|
    class_eval do
      @@locks ||= {}

      names.each do |name|
        # make a lock for each attribute
        @@locks[name] = Mutex.new

        # getter
        define_method(name) do
          @@locks[name].synchronize do
            instance_variable_get("@#{name}")
          end
        end

        # setter
        define_method("#{name}=") do |value|
          @@locks[name].synchronize do
            instance_variable_set("@#{name}", value)
            sleep 5
          end
        end

      end

    end # class_eval
  end # attr_locked

end # instance_eval

end
end

class DooWop
include Locker
attr_locked :chord, :name

def initialize name, chord
@name, @chord = name, chord
end
end

x = DooWop.new(‘The Platters’, ‘Fmaj6/9’)

$stdout.sync = true
def tprint string
print “#{Thread.current} #{string}\n”
end

Thread.new{ tprint “1. #{x.name}” }

this will block access to x.name for 5 seconds

Thread.new{ tprint “2. setting name”; x.name = ‘The Orioles’ }

this will wait for the above thread to finish

Thread.new{ sleep 1; tprint “3. #{x.name}” }

this isn’t blocked

Thread.new{ tprint “4. #{x.chord}” }

this will block access to x.chord for 5 seconds

Thread.new do
tprint “5. setting chord”
x.chord = ‘Dm7b5’
tprint “5. #{x.chord}”
end

this could be indeterminite, we didn’t wait for the writer to finish

Thread.new{ tprint “6. unsafe: #{x.instance_eval{@name}}” }

sleep 0.5 until Thread.list.size == 1 # should be joining here instead

This is helpful only in the simplest cases. First it blocks everyone
while in the getter or setter… ideally we shouldn’t make the getters
wait for the other getters to finish. Next, if you try to read the
variable more than once in a method, you can still end up with
different values.

You’d need to wrap the section of code that involves the var in a
#synchronize block… but wrap the least amount of code necessary
because you want to hurry up and let the other threads do their work.
There’s no way to “automate” that. The code above is only useful in
the most simple applications.

Further, we’ve only been talking about one variable at a time. Often
you’ll need to lock several variables, like maybe we are going to look
up on Google which songs by @name have the chord @chord. We’ll need
to get those values at the same time because if we read chord,
(another thread interrupts here and changes @name), then read name…
that’s a problem, and our “locked” variables can’t do anything to
help.

There was a thread on this list a few days ago with a title like
“synchronized attr”, I only skimmed it but I think they were talking
about why you can’t really boil thread synchronization down to a
one-size-fits-all solution. There are a few data structures (Monitor,
ConditionVariable, Queue, etc) that really help out, but there’s no
way to just call some method to magically make your code thread
safe… yet?

Regards,
Erwin

On 6/16/07, Trans [email protected] wrote:
.

Also, I was thinking. If it’s thread safe to just pass type as an
argument, one would think there could be a way to define a “locked”
instance var that is essentially the same thing but without all the
overhead.
Hmm I am afraid that is impossible, there was a very recent discussion
about it,
it might of course be sufficient to lock the ivar accessors and be
confident that the contract (of accessing the ivar by means of the
accessors only) is respected.

Robert

On Jun 16, 3:52 am, “Erwin A.” [email protected] wrote:

...

argument, one would think there could be a way to define a “locked”
about… I had trouble getting the methods put in the right namespace,
class_eval do
end
end
attr_locked :chord, :name
print “#{Thread.current} #{string}\n”

this isn’t blocked

Thread.new{ tprint “6. unsafe: #{x.instance_eval{@name}}” }
#synchronize block… but wrap the least amount of code necessary
help.

There was a thread on this list a few days ago with a title like
“synchronized attr”, I only skimmed it but I think they were talking
about why you can’t really boil thread synchronization down to a
one-size-fits-all solution. There are a few data structures (Monitor,
ConditionVariable, Queue, etc) that really help out, but there’s no
way to just call some method to magically make your code thread
safe… yet?

I was thinking more along the lines of “transparent arguments”. Here’s
the idea in pseudo-code. I’ll represent these “transparent arguments”
via an underscore.

class Q

def f
  _t = "world"
  g("hello")
end

def g(x)
  puts x + ' ' + _t
  h("goodbye")
end

def h(x)
  puts x + ' ' + _t
end

end

Q.new.f

produces

hello world
goodbye world

In effect, _t is being tacked on to the arguments of every call, and
is thus getting passed around just like any other argument, but
without need to explicitly “slot” for it in the method interface. In
effect, transparent arguments are a sort of symbiosis of instance var
and argument. Now, I know that some will see this and think it a
violation of the very purpose of functions, ie. the isolation of name
spaces. However, one should see these as a form of instance var, not
argument --they differ only in that they piggy back on the argument
passing mechanism.

T.

On 16.06.2007 06:50, Trans wrote:

    run

more than once in the #run method, you might even get different values
them), but I think the best way to make your code thread safe is to
somewhere, like #initialize but that doesn’t typically cause thread
to your actual non-example code though.
@ary = ary
class TypeRunner
attr :type
def initialize(type)
@type = type
end

 def run
   puts type
 end

end

You can do it differently by using command pattern:

X = Struct.new :ary do
def go
TypeRunner.new(ary).go
end
end

TypeRunner = Struct.new :type do
def go
type.each {|x| self.type = x; run}
end

def run
end
end

or

X = Struct.new :ary do
def go
tr = TypeRunner.new(ary)
ary.each {|x| tr.type = x; tr.run}
end
end

TypeRunner = Struct.new :type do
def run
end
end

X.new([‘a’, ‘b’, ‘c’]).go

Am I right about this being thread safe® where the first version was
not?

Yes, the concept is known as “thread confinement”. You create an
instance that by design is used by a single thread only.

Also, I was thinking. If it’s thread safe to just pass type as an
argument, one would think there could be a way to define a “locked”
instance var that is essentially the same thing but without all the
overhead.

An instance var that is the same thing as an argument? I have no idea
what that is. You could use thread local variables but I suggest to use
those sparingly as they make code hard to read and understand - explicit
passing is better IMHO. Also, implicit transfer might cause unwanted
side effects (e.g. two completely unrelated pieces of code using the
same name for a thread local).

Kind regards

robert

Wow, you’re meddling in some pretty interesting things here. I don’t
think Ruby is that fit for them, however.

Forth is a language without arguments. You just have a stack shared by
all. It’s elegant as hell and I love it, and it’s first on my list of
things to meddle with seriously.

Forth code looks like this:

: fib-iter ( n – f ) ( things in braces are comments )
0 1 rot 0 ?do over + swap loop drop ;

Here’s an explanation:
http://en.literateprograms.org/Fibonacci_numbers_(Forth)#chunk%20def:fib-iter

Ask Ed Borasky. He’s very enthusiastic about it.

Your later ideas sound to me a bit like Haskell monads, of which I’ve
read a very good explanation recently that I’ve forgot the link for
(there’s a whole industry of trying to explain what monads are).

Aur

On Jun 17, 3:27 pm, SonOfLilit [email protected] wrote:

0 1 rot 0 ?do over + swap loop drop ;

Here’s an explanation:http://en.literateprograms.org/Fibonacci_numbers_(Forth)#chunk%20def:

Does my FORTH love show thru? ;D

Yes, I very much love that language, and have secret plans to
rendezvous with her again one day.

Ask Ed Borasky. He’s very enthusiastic about it.

Your later ideas sound to me a bit like Haskell monads, of which I’ve
read a very good explanation recently that I’ve forgot the link for
(there’s a whole industry of trying to explain what monads are).

When it comes to monads, I got as far as Leibnitz and from what I’ve
read since I think that might be wise :wink:

T.

Your later ideas sound to me a bit like Haskell monads, of which I’ve
read a very good explanation recently that I’ve forgot the link for
(there’s a whole industry of trying to explain what monads are).

http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html

Aur

On 6/18/07, Trans [email protected] wrote:

Does my FORTH love show thru? ;D

Yes, I very much love that language, and have secret plans to
rendezvous with her again one day.

http://vividpicture.com/aleks/atari/forth.jpg

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs