require 'mutex_m'

class Philosopher
  def initialize(name, left_fork, right_fork)
    @name = name
    @left_fork = left_fork
    @right_fork = right_fork
    @meals = 0
  end

  def go
    while @meals < 5
      think
      dine
    end
    puts 
  end

  def think
    puts 
    sleep(rand())
    puts 
  end

  def dine
    fork1, fork2 = @left_fork, @right_fork
    while true
      pickup(fork1, :wait => true)
      puts 
      if pickup(fork2, :wait => false)
        break
      end
      puts 
      release(fork1)
      fork1, fork2 = fork2, fork1
    end
    puts 

    puts 
    sleep(rand())
    puts 
    @meals += 1

    release(@left_fork)
    release(@right_fork)
  end

  def pickup(fork, opt)
    puts 
    opt[:wait]? fork.mutex.mu_lock: fork.mutex.mu_try_lock
  end

  def release(fork)
    puts 
    fork.mutex.unlock
  end
end

n = 5

Fork = Struct.new(:fork_id, :mutex)
forks = Array.new(n) {|i| Fork.new(i, Object.new.extend(Mutex_m))}

philosophers = Array.new(n) do |i| 
                 Thread.new(i, forks[i], forks[(i+1)%n]) do |id, f1, f2|
                   ph = Philosopher.new(id, f1, f2).go
                 end
               end

philosophers.each {|thread| thread.join}