How to resolve the algorithm Dining philosophers step by step in the F# programming language
How to resolve the algorithm Dining philosophers step by step in the F# programming language
Table of Contents
Problem Statement
The dining philosophers problem illustrates non-composability of low-level synchronization primitives like semaphores. It is a modification of a problem posed by Edsger Dijkstra. Five philosophers, Aristotle, Kant, Spinoza, Marx, and Russell (the tasks) spend their time thinking and eating spaghetti. They eat at a round table with five individual seats. For eating each philosopher needs two forks (the resources). There are five forks on the table, one left and one right of each seat. When a philosopher cannot grab both forks it sits and waits. Eating takes random time, then the philosopher puts the forks down and leaves the dining room. After spending some random time thinking about the nature of the universe, he again becomes hungry, and the circle repeats itself. It can be observed that a straightforward solution, when forks are implemented by semaphores, is exposed to deadlock. There exist two deadlock states when all five philosophers are sitting at the table holding one fork each. One deadlock state is when each philosopher has grabbed the fork left of him, and another is when each has the fork on his right. There are many solutions of the problem, program at least one, and explain how the deadlock is prevented.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Dining philosophers step by step in the F# programming language
Source code in the fsharp programming language
open System
let flip f x y = f y x
let rec cycle s = seq { yield! s; yield! cycle s }
type Agent<'T> = MailboxProcessor<'T>
type Message = Waiting of (Set<int> * AsyncReplyChannel<unit>) | Done of Set<int>
let reply (c: AsyncReplyChannel<_>) = c.Reply()
let strategy forks waiting =
let aux, waiting = List.partition (fst >> flip Set.isSubset forks) waiting
let forks = aux |> List.map fst |> List.fold (-) forks
List.iter (snd >> reply) aux
forks, waiting
let waiter strategy forkCount =
Agent<_>.Start(fun inbox ->
let rec loop forks waiting =
async { let forks, waiting = strategy forks waiting
let! msg = inbox.Receive()
match msg with
| Waiting r -> return! loop forks (waiting @ [r])
| Done f -> return! loop (forks + f) waiting }
loop (Set.ofList (List.init forkCount id)) [])
let philosopher (waiter: Agent<_>) name forks =
let rng = new Random()
let forks = Set.ofArray forks
Agent<_>.Start(fun inbox ->
let rec loop () =
async { printfn "%s is thinking" name
do! Async.Sleep(rng.Next(100, 500))
printfn "%s is hungry" name
do! waiter.PostAndAsyncReply(fun c -> Waiting (forks, c))
printfn "%s is eating" name
do! Async.Sleep(rng.Next(100, 500))
printfn "%s is done eating" name
waiter.Post(Done (forks))
return! loop () }
loop ())
[<EntryPoint>]
let main args =
let forks = Seq.init 5 id |> cycle |> Seq.windowed 2 |> Seq.take 5 |> Seq.toList
let names = ["plato"; "aristotel"; "kant"; "nietzsche"; "russel"]
let waiter = waiter strategy 5
List.map2 (philosopher waiter) names forks |> ignore
Console.ReadLine() |> ignore
0
You may also check:How to resolve the algorithm Gray code step by step in the PARI/GP programming language
You may also check:How to resolve the algorithm Greatest element of a list step by step in the Yorick programming language
You may also check:How to resolve the algorithm Percolation/Site percolation step by step in the Go programming language
You may also check:How to resolve the algorithm Loops/Downward for step by step in the Sather programming language
You may also check:How to resolve the algorithm Concurrent computing step by step in the Sidef programming language