diff --git a/SteveToggiTim/DiningPhilosophers.kt b/SteveToggiTim/DiningPhilosophers.kt new file mode 100644 index 0000000..6349e09 --- /dev/null +++ b/SteveToggiTim/DiningPhilosophers.kt @@ -0,0 +1,123 @@ +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + +class Fork(id: String) : Observable(id) { + + //TODO + // --------------- EDIT CODE BELOW --------------- + + val lock = Mutex() + + suspend fun take(philosopher: String) = lock.withLock { + setOccupiedBy(philosopher) + } + + suspend fun release() { + setOccupiedBy(null) + } + + // --------------- EDIT CODE ABOVE --------------- + + private suspend fun setOccupiedBy(philosopher: String?) { + delay(5L) + onChange(philosopher) + occupiedBy = philosopher + } + + private var occupiedBy: String? = null + + fun available() = occupiedBy == null +} + +class Philosopher( + id: String, + private val leftFork: Fork, + private val rightFork: Fork, +) : Observable(id) { + + //TODO + // --------------- EDIT CODE BELOW --------------- + + suspend fun start() = repeat(10) { + think() + takeForks() + eat() + releaseForks() + }.also { changeState("FINISHED") } + + private suspend fun takeForks() { + while (!forksavailable()) { + wait() + } + leftFork.take(id) + rightFork.take(id) + } + + private fun forksavailable() : Boolean { + return leftFork.available() && rightFork.available() + } + + private suspend fun releaseForks() { + leftFork.release() + rightFork.release() + } + + // --------------- EDIT CODE ABOVE --------------- + + private suspend fun wait() { + delay(1) + } + + private suspend fun eat() { + changeState("EATING") + delay((0L..10L).random()) + } + + private suspend fun think() { + changeState("THINKING") + delay((0L..10L).random()) + changeState("HUNGRY") + } + + private suspend fun changeState(state: String) { + onChange(state) + this.state = state + } + + private var state = "THINKING" +} + +open class Observable(val id: String) { + var onChange: suspend (String, T) -> Unit = { _, _ -> } + protected suspend fun onChange(state: T) = onChange(id, state) +} + +suspend fun main(args: Array) = runBlocking { + val number = 5 + val forks = Array(number) { Fork("Fork$it") } + val philosophers = Array(number) { index -> + Philosopher( + id = "Philosopher$index", + leftFork = forks[index], + rightFork = forks[(index + 1) % number] + ) + } + + philosophers.forEach { + it.onChange = { philosopher, state -> + println("$philosopher is now $state") + } + } + forks.forEach { + it.onChange = { fork, philosopher -> + println(philosopher?.let { "$fork acquired by $it" } ?: "$fork released") + } + } + + philosophers.forEach { + launch { it.start() } + } +}