T
Tassilo Horn
Hi,
I still have some problems with my teadrinker app. After I implemented
the things SER told me in
Message-ID: <[email protected]>
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
I still have some problems with my teadrinker app. After I implemented
the things SER told me in
Message-ID: <[email protected]>
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