サンタクロース問題を解く(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. (略)
追記:
- このRuby版をsumimさんがSqueak Smalltalkに移植なさいました。感謝。