サンタクロース問題を解く(Ruby)

サンタクロース問題Rubyで書いてみました(via サンタクロース問題を Squeak Smalltalk で)。あちこちまだ変ですが、とりあえず公開。

require 'thread'

REINDEER_NUM = 9
ELF_NUM = 10
DISCUSS_NUM = 3

mutex = Mutex.new
santa_cv = ConditionVariable.new
reindeer_queue = Queue.new
elf_queue = Queue.new

def random_sleep
  sleep(rand(3))
end

santa = Thread.new do
  loop do
    mutex.synchronize {
      puts "Santa waits."

      # Wait.
      while !(reindeer_queue.size == REINDEER_NUM || elf_queue.size >= DISCUSS_NUM)
        santa_cv.wait(mutex)
      end

      # Work with reindeers.
      if reindeer_queue.size == REINDEER_NUM
        puts "Santa works with #{REINDEER_NUM} reindeers."
        REINDEER_NUM.times do |k|
          cv = reindeer_queue.deq
          # puts "#{cv.name} is dequeued."
          cv.signal
        end
      end

      # Talk with elves.
      if elf_queue.size >= DISCUSS_NUM
        puts "Santa talks with #{DISCUSS_NUM} elves."
        DISCUSS_NUM.times do |k|
          cv = elf_queue.deq
          # puts "#{cv.name} is dequeued."
          cv.signal
        end
      end
    }
  end
end

class ConditionVariable
  attr_accessor :name
end

reindeers = (1..REINDEER_NUM).collect do |k|
  Thread.new("Reindeer No.#{k}") do |name|
    cv = ConditionVariable.new
    cv.name = name
    loop do
      random_sleep
      # puts "#{cv.name} comes."
      mutex.synchronize {
        reindeer_queue.enq(cv)
        santa_cv.signal
        cv.wait(mutex)
      }
    end
  end
end

elves = (1..ELF_NUM).collect do |k|
  Thread.new("Elf No.#{k}") do |name|
    cv = ConditionVariable.new
    cv.name = name
    loop do
      random_sleep
      # puts "#{cv.name} comes."
      mutex.synchronize {
        elf_queue.enq(cv)
        santa_cv.signal
        cv.wait(mutex)
      }
    end
  end
end

reindeers.each do |t|
  t.join
end
elves.each do |t|
  t.join
end
santa.join

実行結果です。

Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa works with 9 reindeers.
Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa talks with 3 elves.
Santa waits.
Santa works with 9 reindeers.
Santa waits.
Santa talks with 3 elves.
(略)

追記: