2013-02-14 123 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