From: Kenosis Date: 2007-01-04T07:15:08+09:00 Subject: Re: Problem in Unit Testing Methods that start new threads 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