Created
February 16, 2024 14:23
-
-
Save fancellu/b0b6d63d479ed9dc56b4d9547d7d8dc3 to your computer and use it in GitHub Desktop.
Dining Philosophers with Cats Effect
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 cats.effect.std.Semaphore | |
import cats.effect._ | |
import cats.implicits._ | |
import scala.concurrent.duration._ | |
object DiningPhilosophersIOApp extends IOApp { | |
case class Fork(id: Int, lock: Semaphore[IO]) | |
case class Philosopher(name: String, left: Fork, right: Fork) | |
val random = new scala.util.Random(System.currentTimeMillis()) | |
def run(args: List[String]): IO[ExitCode] = { | |
val FORK_COUNT = 7 | |
val forks = (0 until FORK_COUNT).map { id => | |
Semaphore[IO](1).map(id -> Fork(id, _)) | |
}.toList.sequence.map(_.toMap) | |
for { | |
forkMap <- forks | |
// create philosophers, give them forks | |
philosophers: Seq[Philosopher] = (0 until FORK_COUNT).map { id => | |
val left = forkMap(id) | |
val right = forkMap((id + 1) % FORK_COUNT) | |
Philosopher(s"Philosopher $id", left, right) | |
}.toList | |
// spin them up in parallel | |
fibres <- philosophers.traverse(eat(_).start) | |
// wait for them to finish | |
_ <- fibres.toList.map(_.joinWithUnit).sequence | |
} yield ExitCode.Success | |
} | |
def eat(philosopher: Philosopher): IO[Unit] = for { | |
left_id <- philosopher.left.id.pure[IO] | |
right_id <- philosopher.right.id.pure[IO] | |
(firstFork: Fork, secondFork: Fork) <- IO { | |
if (left_id < right_id) | |
(philosopher.left, philosopher.right) | |
else | |
(philosopher.right, philosopher.left) | |
} | |
_ <- firstFork.lock.acquire | |
_ <- secondFork.lock.acquire | |
_ <- IO.println(s"${philosopher.name} picked up fork $left_id and $right_id") | |
random_delay <- IO(400 + random.nextLong(400)) | |
_ <- IO.println(s"${philosopher.name} is sleeping for $random_delay") | |
_ <- IO.sleep(random_delay.millis) | |
_ <- IO.println(s"${philosopher.name} is done eating") | |
_ <- secondFork.lock.release | |
_ <- firstFork.lock.release | |
} yield () | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output
Philosopher 2 picked up fork 2 and 3
Philosopher 5 picked up fork 5 and 6
Philosopher 0 picked up fork 0 and 1
Philosopher 5 is sleeping for 717
Philosopher 2 is sleeping for 536
Philosopher 0 is sleeping for 708
Philosopher 2 is done eating
Philosopher 0 is done eating
Philosopher 1 picked up fork 1 and 2
Philosopher 1 is sleeping for 623
Philosopher 5 is done eating
Philosopher 6 picked up fork 6 and 0
Philosopher 6 is sleeping for 515
Philosopher 4 picked up fork 4 and 5
Philosopher 4 is sleeping for 514
Philosopher 6 is done eating
Philosopher 4 is done eating
Philosopher 3 picked up fork 3 and 4
Philosopher 3 is sleeping for 576
Philosopher 1 is done eating
Philosopher 3 is done eating