Ruby を使い始めてまだ 1 週間も経っていませんが、すでにこの言語の威力を実感しています。私は、オレンジ ツリーとして実装された、古典的な生産者と消費者の問題を解決しようとしています ( http://pine.fm/LearnToProgram/?Chapter=09を参照)。オレンジの木は枯れるまで毎年成長し、毎年ランダムな数のオレンジを生産します (生産者)。オレンジは、木の上にある限り摘むことができます (消費者)。
ここには2つの問題があります:
次のコードでは、次の例外が発生します (添付できません、オプションはありません)。
/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 `'
マルチスレッド部分が正しくコーディングされているかどうかはわかりません。
「プログラミング 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