Last active
December 30, 2015 08:16
-
-
Save bugant/4984042 to your computer and use it in GitHub Desktop.
Dining Philosophers solution using Celluloid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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