Skip to content

Instantly share code, notes, and snippets.

@bugant
Last active December 30, 2015 08:16
Show Gist options
  • Save bugant/4984042 to your computer and use it in GitHub Desktop.
Save bugant/4984042 to your computer and use it in GitHub Desktop.
Dining Philosophers solution using Celluloid
#!/usr/bin/env ruby
require 'rubygems'
require 'bundler/setup'
require 'celluloid'
class Table
include Celluloid
CHOPSTICK_FREE = 0
CHOPSTICK_USED = 1
attr_reader :philosophers
attr_reader :chopsticks
attr_reader :eating
def initialize(chopsticks)
@philosophers = []
@eating = []
@chopsticks = Array.new(chopsticks, CHOPSTICK_FREE)
end
def welcome(philosopher)
@philosophers << philosopher
philosopher.async.think
end
def hungry(philosopher)
pos = @philosophers.index(philosopher)
abort RuntimeError.new('A philosopher is not even sat down') if pos.nil?
left_pos = pos
right_pos = (pos + 1) % @chopsticks.size
if [@chopsticks[left_pos], @chopsticks[right_pos]].all? {|status| status == CHOPSTICK_FREE}
@chopsticks[left_pos] = CHOPSTICK_USED
@chopsticks[right_pos] = CHOPSTICK_USED
@eating << philosopher
print_table_status(pos)
philosopher.async.eat
abort RuntimeError.new('TOO MANY PHILOSOPHER ARE EATING') if @eating.size == @chopsticks.size
puts "TABLE: #{@eating.size} are eating"
else
# it's not your turn, keep thinking
print_table_status(pos)
philosopher.async.think
end
end
def drop_chopsticks(philosopher)
pos = @philosophers.index(philosopher)
abort RuntimeError.new('A philosopher is not even sat down') if pos.nil?
left_pos = pos
right_pos = (pos + 1) % @chopsticks.size
if ! [@chopsticks[left_pos], @chopsticks[right_pos]].all? {|status| status == CHOPSTICK_USED}
abort RuntimeError.new('A philosopher without both chopsticks thinks he had eaten')
end
@chopsticks[left_pos] = CHOPSTICK_FREE
@chopsticks[right_pos] = CHOPSTICK_FREE
@eating -= [philosopher]
print_table_status(pos)
philosopher.async.think
end
def print_table_status(pos)
puts "TABLE: EATING: #{eating.map {|p| philosophers.index(p)}}; CHOPSTICKS #{chopsticks}; MY POS: #{pos}"
end
end
class Philosopher
include Celluloid
attr_reader :name
attr_reader :table
def initialize(name, table)
@name = name
@table = table
table.async.welcome(Actor.current)
end
def think
puts "#{name} is thinking"
sleep(rand)
puts "#{name} gets hungry"
table.async.hungry(Actor.current)
end
def eat
puts "#{name} is eating"
sleep(rand)
puts "#{name} burps"
table.async.drop_chopsticks(Actor.current)
end
end
#
# Run the simulation
#
names = %w{Heraclitus Aristotle Epictetus Schopenhauer Popper}
table = Table.new(names.size)
philosophers = names.map {|name| Philosopher.new(name, table)}
# The main thread is done! Sleep forever
sleep
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment