Dining philosophers using locks in Ruby. This implements a Waiter who is in charge of forks.
require 'thread' | |
class Waiter | |
def initialize | |
@mutex = Mutex.new | |
end | |
def can_eat? philosopher | |
left = philosopher.left_fork | |
right = philosopher.right_fork | |
@mutex.synchronize do | |
if !left.used && !right.used | |
left.used = true | |
right.used = true | |
return true | |
else | |
return false | |
end | |
end | |
end | |
def stop_eating philosopher | |
@mutex.synchronize do | |
philosopher.left_fork.used = false | |
philosopher.right_fork.used = false | |
end | |
end | |
end | |
class Philosopher | |
attr_accessor :left_fork, :right_fork | |
def initialize(name, left_fork, right_fork, waiter) | |
@name = name | |
@left_fork = left_fork | |
@right_fork = right_fork | |
@waiter = waiter | |
think | |
end | |
def think | |
puts "Philosopher #@name is thinking..." | |
sleep(rand()) | |
puts "Philosopher #@name is hungry..." | |
dine | |
end | |
def dine | |
while !@waiter.can_eat?(self) | |
think | |
end | |
puts "Philosopher #@name eats..." | |
sleep(rand()) | |
puts "Philosopher #@name belches" | |
@waiter.stop_eating(self) | |
think | |
end | |
end | |
n = 5 | |
forks = [] | |
class Fork | |
attr_accessor :used | |
def initialize | |
@used = false | |
end | |
end | |
(1..n).each do |i| | |
forks << Fork.new | |
end | |
threads = [] | |
waiter = Waiter.new | |
(1..n).each do |i| | |
threads << Thread.new do | |
if i < n | |
left_fork = forks[i] | |
right_fork = forks[i+1] | |
else | |
# special case for philosopher #5 because he gets forks #5 and #1 | |
# and the left fork is always the lower id because that's the one we try first. | |
left_fork = forks[0] | |
right_fork = forks[n] | |
end | |
Philosopher.new(i, left_fork, right_fork, waiter) | |
end | |
end | |
threads.each {|thread| thread.join} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment