From: Hemant Kumar Date: 2007-01-04T12:48:01+09:00 Subject: Re: Problem in Unit Testing Methods that start new threads On Thu, 2007-01-04 at 07:15 +0900, Kenosis wrote: > Hemant Kumar wrote: > > On Thu, 2007-01-04 at 01:04 +0900, ara.t.howard@noaa.gov wrote: > > > > Now, as someone suggested on IRC, I can do a join and wait for the > > > > thread to finish. But the problem is, I don't exactly have an instance > > > > to the thread, because its managed by a plugin and i am just using the > > > > plugin to do stuff. > > > > > > > > Any ideas/suggestions are more than welcome. > > > > > > it seems that all you've managed to do is write a very long race condition. > > > i'm not one of those people who think the mere mention of the word > > > 'unit-testing' bestows any sort of robustness on code. for example, the > > > testing of 'thread_status' in your test means nothing, as it's the source of > > > the race condition: you need to wrap setting and reading this var with a > > > semaphore. this shows why: > > > > > > harp:~ > cat a.rb > > > class C > > > attr :thread > > > def initialize > > > @thread = nil > > > end > > > def new_thread > > > Thread.new{ @thread = Thread.current } > > > end > > > end > > > > > > 4242.times{|i| raise "race condition @ loopno #{ i }!" unless((c = C.new) and (Thread === c.new_thread) and c.thread) } > > > > > > > > > harp:~ > ruby a.rb > > > a.rb:11: race condition @ loopno 942! (RuntimeError) > > > from a.rb:11 > > > > > > > > > > Thanks for the insight Ara, although my class is singleton so i > > shouldn't get the problem you have described above. > > > > However can you show me a code sample, that doesn't cause race condition > > in above code. I tried using Mutex on above code, > > > > require "thread" > > class C > > attr :thread > > def initialize > > mutex = Mutex.new > > mutex.lock > > @thread = nil > > mutex.unlock > > end > > > > def new_thread > > Thread.new{ > > mutex = Mutex.new > > mutex.lock > > @thread = Thread.current > > mutex.unlock > > } > > end > > > > end > > > > 4242.times{|i| raise "race condition @ loopno #{ i }!" unless((c = > > C.new) and (Thread === c.new_thread) and c.thread) } > > > > And I am still getting a race condition. Using MonitorMixin to signal > > execution seems like an overkill to me in above code. > > > > So can you show me a way of making above code not race. > > > > > > > regarding your specific question though, you need to verify that a thread is > > > created and that it's status is running. even if you don't have a handle on > > > the thread you can set things up in your unit test to get one. something like > > > > > > harp:~ > cat a.rb > > > def tracking_threads &b > > > before = Thread.list > > > yield > > > after = Thread.list > > > return after - before > > > end > > > > > > threads = tracking_threads{ 2.times{ Thread.new{ sleep } } } > > > > > > threads.each{|t| p t.status} > > > > > > > > > harp:~ > ruby a.rb > > > "sleep" > > > "sleep" > > > > > > > > > > Cool thanks. > > Try removing the "mutex = Mutex.new" from "new_thread" That's causing a > thread local mutex to be created that's only being used by that thread > and none of the others, because they have their own mutex. The threads > need to share the SAME mutex in order to enable mutual exclusion > between them, ie, the mutex you create in initialize(). That said, us > better understanding what you actually want to unit test would help us > to help you. > > Cheers, > > Ken > Since We are calling new each time, even using instance variables won't solve the race condition. I have even tried using class variables, and I am still getting race condition. Ara, please demonstrate how you would solve the race condition in above shown code of yours?