Skip to content

Instantly share code, notes, and snippets.

@lrodero
Last active March 24, 2024 10:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lrodero/4f6194bcffc3ce32a1780d55176a1ba4 to your computer and use it in GitHub Desktop.
Save lrodero/4f6194bcffc3ce32a1780d55176a1ba4 to your computer and use it in GitHub Desktop.
Implementation of the dining philosophers problem using Cats Effect and Scala 3
//> using scala 3.3
//> using dep org.typelevel::cats-effect:3.5.4
import cats.effect.std.{Random, Semaphore}
import cats.syntax.all.*
import cats.effect.{IO, IOApp}
import scala.concurrent.duration.*
object DiningPhilosophers extends IOApp.Simple:
type Fork = Semaphore[IO]
val createForks = Semaphore[IO](1).replicateA(5)
val createPhilosophers: IO[List[Philosopher]] =
for
forks <- createForks
randomGenerator <- Random.scalaUtilRandom[IO]
philosophers = forks.indices.toList.map: i =>
val leftFork = if (i == 0) forks.last else forks(i - 1)
val rightFork = forks(i)
val (firstFork, secondFork) = if (i==0) (rightFork, leftFork) else (leftFork, rightFork)
Philosopher(firstFork, secondFork, randomGenerator)
yield philosophers
val runPhilosophers: IO[Unit] =
for
philosophers <- createPhilosophers
_ <- philosophers.map(_.doYourThing).parSequence
yield ()
class Philosopher(firstFork: Fork, val secondFork: Fork, random: Random[IO]):
private def randomTime(max: FiniteDuration): IO[FiniteDuration] =
random
.nextLongBounded(max.toNanos)
.map(FiniteDuration(_, NANOSECONDS))
private val think = (randomTime(60.milliseconds) >>= IO.sleep) >> IO.println("Philosopher has finished thinking")
private val eat = (randomTime(30.milliseconds) >>= IO.sleep) >> IO.println("Philosopher has finished eating")
private val getForks = firstFork.acquire >> secondFork.acquire
private val releaseForks = firstFork.release >> secondFork.release
val doYourThing: IO[Unit] = think >> getForks >> eat >> releaseForks >> doYourThing
override val run: IO[Unit] =
runPhilosophers.timeoutTo(1.minute, IO.unit)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment