# Dining philosophers using join calculus

This example shows an implementation of the dining philosophers problem implemented using joinads. The sample has been written by Nick Palladinos (see F# Snippets). The description of the dining philosophers problem from WikiPedia looks like this:

• 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.

The solution using joinads represents each philosopher and a fork (or a chopstick) using a single channel. The initialization code looks like this:

```open System

// Initialize channel for every philosopher and every chopstick
let n = 5
let chopsticks = [| for i = 1 to n do yield new Channel<unit>() |]
let hungry = [| for i = 1 to n do yield new Channel<unit>() |]
let philosophers = [| "Plato"; "Konfuzius"; "Socrates"; "Voltaire"; "Descartes" |]

The situation when a philosopher can start eating is captured by a join pattern that matches on channels representing the philosopher and a fork on the left and on the right:

```// Start join patterns that enable philosophers to eat
for i = 0 to n - 1 do
let left = chopsticks.[i]
let right = chopsticks.[(i+1) % n]
let random = new Random()
join {
match! hungry.[i], left, right with
| _, _, _ ->
printfn "%s is eating" philosophers.[i]
randomDelay random
left.Call(); right.Call()
printfn "%s is thinking" philosophers.[i]
}```

Now we can start the code by making all chopsticks (initially) available and by running a loop that makes random philosophers hungry:

```// Run
for chopstick in chopsticks do
chopstick.Call()

let random = new Random()
for i in 0 .. 10 do
hungry.[random.Next(0, n)].Call()
randomDelay random```
namespace System
namespace FSharp
namespace FSharp.Extensions
val n : int

type: int
inherits: ValueType
val chopsticks : Channel<unit> []

type: Channel<unit> []
inherits: Array
val i : int
type: int
inherits: ValueType
Multiple items
module Channel

--------------------
type Channel<'T> =
class
interface IChannel<'T>
new : unit -> Channel<'T>
member Call : message:'T -> unit
member Put : message:'T -> unit
end

type: Channel<'T>
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
type: unit
val hungry : Channel<unit> []

type: Channel<unit> []
inherits: Array
val philosophers : string []

type: string []
inherits: Array
val randomDelay : Random -> unit

val r : Random
type Random =
class
new : unit -> System.Random
new : int -> System.Random
member Next : unit -> int
member Next : int -> int
member Next : int * int -> int
member NextBytes : System.Byte [] -> unit
member NextDouble : unit -> float
end

Full name: System.Random
class
inherit System.Runtime.ConstrainedExecution.CriticalFinalizerObject
member Abort : unit -> unit
member CurrentCulture : System.Globalization.CultureInfo with get, set
member CurrentUICulture : System.Globalization.CultureInfo with get, set
member GetHashCode : unit -> int
member IsAlive : bool
member IsBackground : bool with get, set
member Join : unit -> unit
member Join : int -> bool
member Name : string with get, set
member Start : unit -> unit
member Start : obj -> unit
static member GetDomain : unit -> System.AppDomain
static member MemoryBarrier : unit -> unit
static member Sleep : int -> unit
static member Sleep : System.TimeSpan -> unit
static member SpinWait : int -> unit
end

inherits: Runtime.ConstrainedExecution.CriticalFinalizerObject
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val left : Channel<unit>
type: Channel<unit>
val right : Channel<unit>
type: Channel<unit>
val random : Random
val join : JoinBuilder