2013-02-14 84 views
0

我前开始关于Ruby不到一周的时间,但是已经走到 欣赏语言的力量。我想在一个经典的 生产者消费者问题我的手,为橙树(C.F. http://pine.fm/LearnToProgram/?Chapter=09)来实现。橙树生长的每个 年,直到它死了,产生橙子每年 (监制)的随机数。只要树上有任何东西(消费者),就可以挑选橘子。红宝石多线程的生产者 - 消费者

我有两个问题在这里:

  1. 下面的代码给我下面的异常(无法连接,没有选项):

     
    /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:84: 
    warning: instance variable @orange_tree not initialized 
    /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:84:in `': 
    
    undefined method `age' for nil:NilClass (NoMethodError) from 
    /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:45:in `' 
    
  2. 我不知道多线程部分被正确编码。

我有几本书,包括“编程Ruby”和“Ruby编程语言”,但都没有包含真正的“生产者 - 消费者问题”。

P.S:对于充分披露的缘故,我也张贴在论坛上的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 

回答

0

@orange_tree是Worker对象的实例变量,只能从对象内部访问。您试图在“直到”条件下从全局范围访问该条件,但条件不存在。有解决这一问题的一些方法,但是这一次,需要最少变化:

... 

orange_tree = OrangeTree.new 
Worker.new(Mutex.new, ConditionVariable.new, orange_tree).do_some_work 
until (orange_tree.age == OrangeTree::AGE_TO_DIE) 
... 

你也应该看看Thread#joinhttp://www.ruby-doc.org/core-1.9.3/Thread.html#method-i-join。它会照顾你的等待。其余的多线程代码在技术上看起来是正确的。我相信你知道,如果这不仅仅是一个练习,你会想让这些互斥体更加细化。因为它们现在是两个线程将几乎相互独立地执行哪种破坏线程的点。

而且,查找attr_accessorattr_reader。他们将节省您不必手动定义OrangeTree#heightage

多加入例如

threads = [] 

threads << Thread.new do 
    ... 
end 

threads << Threads.new do 
    ... 
end 

threads.each { |thread| thread.join } 
+0

让你建议的修改,包括加入后,现在我得到: 橙色选择器临睡前睡觉的5 对不起后5 橙色拾取醒来,没有橘子挑 橙色选择器耐心等待... 年龄增速临睡前2 年龄增速睡了2 012睡醒后/Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:76:in'join':检测到死锁(致命) \t from /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb: 76:在'do_some_work' \t from ... – 2013-02-14 12:25:30

+0

那是在第二个'join'吗?它看起来像上面的例子吗? – bioneuralnet 2013-02-14 16:07:07

+0

下面是一些代码片段(希望我能知道如何对其进行格式化) 结束 orange_picker.join age_increaser.join 结束 工人= Worker.new(Mutex.new,ConditionVariable.new,OrangeTree.new) 工人.do_some_work end – 2013-02-14 16:47:16