簡體   English   中英

Ruby多線程生產者-消費者

[英]Ruby Multithreaded producer-consumer

我不到一周前就開始使用Ruby,但是已經開始欣賞這種語言的強大功能。 我正在嘗試解決一個典型的生產者-消費者問題,該問題已實現為一棵橙樹(參見http://pine.fm/LearnToProgram/?Chapter=09 )。 橘樹每年生長直到死亡,並每年產生隨機數量的橘子(生產者)。 只要樹上有橘子(消費者),就可以采摘橘子。

我這里有兩個問題:

  1. 以下代碼為我提供了以下異常(無法附加,無選項):

    \n /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:84:\n 警告:實例變量@orange_tree未初始化\n /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:84:in'':\n\n 來自的nil:NilClass(NoMethodError)的未定義方法'age'\n /Users/Abhijit/Workspace/eclipse/ruby/learn_to_program/orange_tree.rb:45:in`'\n
  2. 我不確定多線程部分是否正確編碼。

我自己寫了幾本書,包括“ Ruby編程”和“ Ruby編程語言”,但沒有一本書包含真正的“生產者-消費者問題”。

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

@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等的OrangeTree#height

多聯接示例

threads = []

threads << Thread.new do
  ...
end

threads << Threads.new do
  ...
end

threads.each { |thread| thread.join }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM