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