Skip to content

Instantly share code, notes, and snippets.

@fancellu
Last active February 16, 2024 12:17
Show Gist options
  • Save fancellu/b157b364c01ce141ca7d4c09b29981d6 to your computer and use it in GitHub Desktop.
Save fancellu/b157b364c01ce141ca7d4c09b29981d6 to your computer and use it in GitHub Desktop.
Scala implementation of dining philosophers, after doing it in Rust
import java.util.concurrent.Executors
import java.util.concurrent.locks.{Lock, ReentrantLock}
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration.*
import scala.concurrent.ExecutionContext.Implicits.global
case class Fork(id: Int, lock: Lock)
case class Philosopher(name: String, left: Fork, right: Fork)
object DiningPhilosophers {
val random = new scala.util.Random(System.currentTimeMillis())
def eat(philosopher: Philosopher): Unit = {
// choose smallest id fork, to prevent deadlocks
val left_id = philosopher.left.id
val right_id = philosopher.right.id
val (firstFork, secondFork) =
if (left_id < right_id)
(philosopher.left, philosopher.right)
else
(philosopher.right, philosopher.left)
// grab forks
val firstLock = firstFork.lock
val secondLock = secondFork.lock
println(s"${philosopher.name} is picking up fork $left_id and $right_id")
firstLock.lock()
secondLock.lock()
try {
// eat
println(s"${philosopher.name} is eating")
val random_delay = 400 + random.nextLong(400)
println(s"${philosopher.name} is sleeping for $random_delay")
Thread.sleep(random_delay)
println(s"${philosopher.name} is done eating")
} finally {
secondLock.unlock()
firstLock.unlock()
}
}
def main(args: Array[String]): Unit = {
val forkCount = 5
// Using a threadpool
val executor = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(forkCount))
val forks = (0 until forkCount).map { id =>
val lock = new ReentrantLock
Fork(id, lock)
}.toList
val philosophers = (0 until forkCount).map { id =>
val left = forks(id)
val right = forks((id + 1) % forkCount)
Philosopher(s"Philosopher $id", left, right)
}.toList
val futures = philosophers.map { philosopher =>
Future {
eat(philosopher)
}(executor)
}
Await.result(Future.sequence(futures), Duration.Inf)
println("All philosophers have eaten")
executor.shutdown()
}
}
@fancellu
Copy link
Author

Output

Philosopher 1 is picking up fork 1 and 2
Philosopher 3 is picking up fork 3 and 4
Philosopher 3 is eating
Philosopher 4 is picking up fork 4 and 0
Philosopher 0 is picking up fork 0 and 1
Philosopher 2 is picking up fork 2 and 3
Philosopher 3 is sleeping for 655
Philosopher 1 is eating
Philosopher 1 is sleeping for 680
Philosopher 3 is done eating
Philosopher 4 is eating
Philosopher 4 is sleeping for 635
Philosopher 1 is done eating
Philosopher 2 is eating
Philosopher 2 is sleeping for 624
Philosopher 4 is done eating
Philosopher 0 is eating
Philosopher 0 is sleeping for 795
Philosopher 2 is done eating
Philosopher 0 is done eating
All philosophers have eaten

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment