From: Hemant Kumar Date: 2007-01-04T02:22:24+09:00 Subject: Re: Problem in Unit Testing Methods that start new threads 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.