Last active
February 16, 2024 12:17
-
-
Save fancellu/b157b364c01ce141ca7d4c09b29981d6 to your computer and use it in GitHub Desktop.
Scala implementation of dining philosophers, after doing it in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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