From: "ara.t.howard" Date: 2008-08-22T23:26:52+09:00 Subject: Re: Newly created thread blocks all others in Ruby 1.8.7 patchlevel 72 on Cygwin On Aug 19, 2008, at 9:22 AM, Daniel Merk wrote: > require 'thread' > > count1 = count2 = 0 > puts "starting thread a" > a = Thread.new do > loop { count1 += 1 } > end > a.priority = -1 > > puts "starting thread b" > b = Thread.new do > loop { count2 += 1 } > end > b.priority = -2 > sleep 1 #=> 1 > Thread.critical = 1 > > puts "count1: #{count1}" > puts "count2: #{count2}" > > > This code never starts thread b. It seems that thread a blocks all > other threads once it runs (though its priority is lowered), even the > main thread. > If I put a sleep command into the thread a loop, thread b starts, but > the problem remains, since then thread b blocks all others from > running. that code looks completely non-deterministic to me and i've had similar issues many times in the past. i think the fundamental error is mistaking the creation of a thread for scheduling it. i've used the following pattern many times to force my code to know that a thread has started processing before continuing: cfp:~ > ruby186 a.rb starting thread a starting thread b count1: 4580083 count2: 44732 cfp:~ > ruby187 a.rb starting thread a starting thread b count1: 4394267 count2: 37032 cfp:~ > cat a.rb require 'thread' q = Queue.new count1 = count2 = 0 a = Thread.new do puts "starting thread a" q.push Thread.current loop { count1 += 1 } end a = q.pop # wait for the thread to start a.priority = -1 b = Thread.new do puts "starting thread b" q.push Thread.current loop { count2 += 1 } end b = q.pop # wait for the thread to start b.priority = -2 sleep 1 #=> 1 Thread.critical = 1 puts "count1: #{count1}" puts "count2: #{count2}" i'm sorry that i cannot test this on cygwin so i'm not *sure* it's the issue. but to me it simply looks like non-deterministic code. in fact, even the code above has a race condition, i only force the program to ensure each thread calls puts - there is nothing to make sure that stdout has been flushed or that the increments have run in the loop. to do that i think you'd need something like this cfp:~ > cat a.rb require 'thread' q = Queue.new count1 = count2 = 0 a = Thread.new do STDERR.puts "starting thread a" loop do count1 += 1 q.push Thread.current if count1 == 1 end end a = q.pop # wait for the thread to start a.priority = -1 b = Thread.new do puts "starting thread b" q.push Thread.current loop do count2 += 1 q.push Thread.current if count2 == 1 end end b = q.pop # wait for the thread to start b.priority = -2 Thread.critical = 1 puts "count1: #{count1}" puts "count2: #{count2}" cfp:~ > ruby186 a.rb starting thread a starting thread b count1: 19297 count2: 28490 cfp:~ > ruby187 a.rb starting thread a starting thread b count1: 17435 count2: 24603 i'd be curious how that fairs on cygwin. notice that the sleep is not required with the queues. regards. a @ http://codeforpeople.com/ -- we can deny everything, except that we have the possibility of being better. simply reflect on that. h.h. the 14th dalai lama