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