On Jun 15, 11:02 pm, "Erwin Abbott" <erwin.abb... / gmail.com> wrote:
> On 6/15/07, Robert Dober <robert.do... / gmail.com> wrote:> On 6/15/07, Trans <transf... / gmail.com> wrote:
> > > It the following reasonable? How thread safe is it?
> > >     ...
> > >     def go
> > >       @ary.each { |x|
> > >         @type = x
> > -------------------------> Problem, Thread 1 gets interrupted by Thread2
> > -------------------------> Thread2 changes @type
> > >         run
> > >       }
> > >     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.

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(r) 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.

> Regards,
> Erwin