I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Thursday Code Puzzler: Dining Philosophers

05.24.2012
| 5887 views |
  • submit to reddit

By now you should be familiar with our Thursday Code Puzzler slot. The idea is simple: solve the coding problem as efficiently as you can, in any language or framework that you think is suitable.

Note: Even though there really is nothing stopping you from finding a solution to this on the internet, try to keep honest, and come up with your own answer.  It's all about the participation!

The Dining Philosophers Problem

This week's problem is another classic computer science puzzle, which deals with concurrency and trying to avoid deadlocks. The problem statement is as follows (taken from Wikipedia)

Five silent philosophers sit at a table around a bowl of spaghetti. A fork is placed between each pair of adjacent philosophers.Each philosopher must alternately think and eat. Eating is not limited by the amount of spaghetti left: assume an infinite supply.

However, a philosopher can only eat while holding both the fork to the left and the fork to the right (an alternative problem formulation uses rice and chopsticks instead of spaghetti and forks).

Each philosopher can pick up an adjacent fork, when available, and put it down, when holding it. These are separate actions: forks must be picked up and put down one by one.

The problem is how to design a discipline of behavior (a concurrent algorithm) such that each philosopher won't starve, i.e. can forever continue to alternate between eating and thinking.


Try to make the solution as efficient as possible, and if you do get to run it post up your timings, or even better, the Big O notation for your solution.

Comments

Vijay Nathani replied on Thu, 2012/05/24 - 1:24pm

Groovy solution (using open source library GPars) is mentioned below:

#!/usr/bin/env groovy

import static groovyx.gpars.GParsPool.withPool
import java.util.concurrent.*
import groovy.transform.*

int NUMBER_OF_ENTITIES = 5

@Canonical class Philosopher {
    int number
    Semaphore spoon1, spoon2
    private def waitForRandomTime(task) {
        println "Philosopher ${number} is ${task}"
        int MAX_WAITING_TIME = 1000
        sleep(ThreadLocalRandom.current().nextLong(MAX_WAITING_TIME))
    }
    private def oneCycle() {
        waitForRandomTime("Thinking") 
        spoon1.acquire()
        spoon2.acquire()
        waitForRandomTime("Eating")
        spoon2.release()
        spoon1.release()
    }
    def run() {
        while (true) oneCycle()
    }
}
def spoons = (1..NUMBER_OF_ENTITIES).collect { new Semaphore(1) }
def philosopers = (1..NUMBER_OF_ENTITIES).collect {
    (it != NUMBER_OF_ENTITIES) ?
        new Philosopher(it, spoons[it - 1], spoons[it]) :
        new Philosopher(it, spoons.first(), spoons.last()) //NO DEADLOCK
}
withPool (NUMBER_OF_ENTITIES) {
    philosopers.eachParallel { it.run() }
}

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.