0

Ruby を使い始めてまだ 1 週間も経っていませんが、すでにこの言語の威力を実感しています。私は、オレンジ ツリーとして実装された、古典的な生産者と消費者の問題を解決しようとしています ( http://pine.fm/LearnToProgram/?Chapter=09を参照)。オレンジの木は枯れるまで毎年成長し、毎年ランダムな数のオレンジを生産します (生産者)。オレンジは、木の上にある限り摘むことができます (消費者)。

ここには2つの問題があります:

  1. 次のコードでは、次の例外が発生します (添付できません、オプションはありません)。

    /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 `'
    
  2. マルチスレッド部分が正しくコーディングされているかどうかはわかりません。

「プログラミング Ruby」や「The 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
4

1 に答える 1

0

@orange_treeWorker オブジェクトのインスタンス変数であり、オブジェクト内からのみアクセスできます。「until」条件で、存在しないグローバルスコープからアクセスしようとしています。これに対処するにはいくつかの方法がありますが、これは最も少ない変更で済みます。

...

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

http://www.ruby-doc.org/core-1.9.3/Thread.html#method-i-joinも調べてThread#joinください。それはあなたを待っている世話をします。マルチスレッド コードの残りの部分は、技術的には正しいように見えます。これが演習以上のものであれば、ミューテックスをより細かくしたいと思うでしょう。現在のように、2 つのスレッドはほぼ相互に排他的に実行され、スレッドのポイントを無効にします。

また、attr_accessorまたはを参照してくださいattr_readerOrangeTree#heightageなどを手動で定義する必要がなくなります。

複数結合の例

threads = []

threads << Thread.new do
  ...
end

threads << Threads.new do
  ...
end

threads.each { |thread| thread.join }
于 2013-02-14T06:43:18.207 に答える