Skip to content

Instantly share code, notes, and snippets.

@seanlilmateus
Created June 20, 2012 18:02
Show Gist options
  • Save seanlilmateus/2961258 to your computer and use it in GitHub Desktop.
Save seanlilmateus/2961258 to your computer and use it in GitHub Desktop.
Macruby and Rubymotion GCD Semaphore example (The Dining Philosophers Problem)
#!/usr/bin/env macruby -wKU
class Philosopher
def initialize(name, left_chopstick, right_chopstick)
@name = name
@left_chopstick = left_chopstick
@right_chopstick = right_chopstick
@meals = 0
end
def run
while @meals < 5
think
dine
end
puts "philosopher: #@name is full!"
end
def think
puts "philosopher: #@name is thinking..."
sleep(rand())
puts "philosopher: #@name is hungry..."
end
def dine
chopstick1, chopstick2 = @left_chopstick, @right_chopstick
while true
pickup(chopstick1, :wait => true)
puts "philosopher: #@name has chopstick #{chopstick1.id}..."
break if pickup(chopstick2, :wait => false)
puts "philosopher: #@name cannot pickup second chopstick #{chopstick2.id}..."
release(chopstick1)
chopstick1, chopstick2 = chopstick2, chopstick1
end
puts "philosopher: #@name has the second chopstick #{chopstick2.id}..."
puts "philosopher: #@name eats..."
sleep(rand())
puts "philosopher: #@name belches"
@meals += 1
release(@left_chopstick)
release(@right_chopstick)
end
def pickup(chopstick, opt)
puts "philosopher: #@name attempts to pickup chopstick #{chopstick.id}..."
chopstick.wait(opt)
end
def release(chopstick)
puts "philosopher: #@name releases chopstick #{chopstick.id}..."
chopstick.release
end
end
# we just wrappe the semaphores
class Chopstick < Struct.new(:id, :semaphore)
def release
semaphore.signal
end
def wait(opt={})
semaphore.wait(opt[:wait] ? Dispatch::TIME_FOREVER : Dispatch::TIME_NOW)
end
end
philosophers = %W{Aristotle Kant Spinoza Marx Russell}
size = philosophers.length
chopsticks = Array.new(size) { |i| Chopstick.new(i+1, Dispatch::Semaphore.new(1)) }
queue = Dispatch::Queue.concurrent("de.mateus.philosophers.problem")
group = Dispatch::Group.new
philosophers.each_with_index do |name, idx|
queue.async(group) do
cs1 = chopsticks[idx]
cs2 = chopsticks[(idx+1)%size]
Philosopher.new(name, cs1, cs2).run
end
end
# since we want to see the out put, he have to wait till all the dispatch tasks are done
group.wait
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment