From: Tassilo Horn Date: 2004-10-15T21:39:34+09:00 Subject: Again some problem with my multithreaded teadrinker app Hi, I still have some problems with my teadrinker app. After I implemented the things SER told me in Message-ID: <1097253853.581059.173460@z14g2000cwz.googlegroups.com> the program works very good for 3 drinkers. Now I wanted it to support more than 3 drinker Threads. Here's the code: <----- CODE -----> #! /usr/bin/env ruby require 'thread' # For synchronisation mutex = Mutex.new drinker_cv = ConditionVariable.new waiter_cv = ConditionVariable.new # items on the table: # 0: cup # 1: water # 2: tea table = [] items = %w{ Cup Water Tea } # min. 3 drinkers. if ARGV[0].to_i >= 3 drinkers_count = ARGV[0].to_i else drinkers_count = 3 end drinkers_count.times do |i| case i%3 when 0 # this drinker has water and tea needs = [1,2] when 1 # this drinker has a cup and tea needs = [0,2] when 2 # this drinker has a cup and water needs = [0,1] end Thread.new { puts "Starting Drinker#{i}" mutex.synchronize { while true drinker_cv.wait(mutex) # The things on the table are the things the waiter needs. if needs.sort == table.sort puts "Drinker#{i}: #{items[table[0]]} and #{items[table[1]]} on table. I'll cook my tea!" # The Drinker took the items from the table. Now it's empty # till the waiter puts new items on it. table = [] sleep 1 # (1) # puts "Drinker#{i}: Drinking my tea. I call the waiter again." # Wake up the waiter Thread waiter_cv.signal sleep 1 # (2) # puts "Drinker#{i}: Now I'll read my newspaper." end end } } end waiter = Thread.new { mutex.synchronize { while true puts "WAITER: Looking at the table!" if table.length == 0 puts "WAITER: Oh, nothing on the table!" #sleep 2 while table[0] == table[1] do table = [rand(3), rand(3)] end $stdout << "WAITER: Putting " << table[0] << " and " << table[1] << " on the table.\n" else puts "WAITER: Why did you call me???" end # Call waiting tea drinkers. drinker_cv.broadcast # (3) # puts "WAITER: Waiting for new appointments..." waiter_cv.wait(mutex) end } } waiter.join <----- END_OF_CODE -----> If I start it with let's say 20 drinkers (./TeaRoom.rb 20) it starts all threads, but only the drinkers 0..2 cook their tea. If the table contains the items 1 and 2 always drinker0 will cook his tea although drinker3, drinker6, drinker9 etc need the same items. Why is it the way it is and how do I get it the way I want which means that the probability of using drinkerX is the same as using drinkerX+-3? Why does drinker_cv.broadcast (line marked with '# (3) #') always wake up the same threads? One interesting this is that if I remove the lines '# (2) #' and '# (2) #' (the sleep() method calls) more drinkers get their turn. But still there are drinkers who never drink a tea and others who extremely often have to drink. Can anybody help me before any of my tearoom customers die with thirst or because of too much tea? Thanks, Tassilo