不到一周前,我开始使用 Ruby,但已经开始欣赏这种语言的力量。我正在尝试解决一个经典的生产者-消费者问题,以橙树的形式实现(参见 http://pine.fm/LearnToProgram/?Chapter=09)。橘子树每年都在生长,直到它死去,并且每年生产随机数量的橘子(生产者)。只要树上有橙子就可以采摘(消费者)。
我这里有两个问题:
以下代码给了我以下异常(无法附加,没有选项):
/Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:84: 警告:实例变量@orange_tree 未初始化 /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:84:in `': nil:NilClass (NoMethodError) 的未定义方法‘age’来自 /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:45:in `'
我不确定多线程部分是否正确编码。
我自己有几本书,包括“Programming Ruby”和“The Ruby Programming Language”,但没有一本包含真正的“生产者-消费者问题”。
PS:为了充分披露,我也在 Ruby 论坛上发布了这个问题。但是,我在这里看到了出色的答案和/或建议,并希望我也能得到其中的一些。
require 'thread'
class OrangeTree
GROWTH_PER_YEAR = 1
AGE_TO_START_PRODUCING_ORANGE = 3
AGE_TO_DIE = 7
ORANGE_COUNT_RELATIVE_TO_AGE = 50
def initialize
@height = 0
@age = 0
@orange_count = 0
end
def height
return @height
end
def age
return @age
end
def count_the_oranges
return @orange_count
end
def one_year_passes
@age += 1
@height += GROWTH_PER_YEAR
@orange_count = Math.rand(@age..AGE_TO_DIE) * Math.log(@age) * ORANGE_COUNT_RELATIVE_TO_AGE
end
def pick_an_orange
if (@age == AGE_TO_DIE)
puts "Sorry, the Orange tree is dead"
elsif (@orange_count > 0)
@orange_count -= 1
puts "The Orange is delicious"
else
puts "Sorry, no Oranges to pick"
end
end
end
class Worker
def initialize(mutex, cv, orange_tree)
@mutex = mutex
@cv = cv
@orange_tree = orange_tree
end
def do_some_work
Thread.new do
until (@orange_tree.age == OrangeTree.AGE_TO_DIE)
@mutex.synchronize do
sleep_time = rand(0..5)
puts "Orange picker going to sleep for #{sleep_time}"
sleep(sleep_time)
puts "Orange picker woke up after sleeping for #{sleep_time}"
@orange_tree.pick_an_orange
puts "Orange picker waiting patiently..."
@cv.wait(@mutex)
end
end
end
Thread.new do
until (@orange_tree.age == OrangeTree.AGE_TO_DIE)
@mutex.synchronize do
sleep_time = rand(0..5)
puts "Age increaser going to sleep for #{sleep_time}"
sleep(sleep_time)
puts "Age increaser woke up after sleeping for #{sleep_time}"
@orange_tree.one_year_passes
puts "Age increaser increased the age"
@cv.signal
end
end
end
end
Worker.new(Mutex.new, ConditionVariable.new, OrangeTree.new).do_some_work
until (@orange_tree.age == OrangeTree.AGE_TO_DIE)
# wait for the Threads to finish
end
end