How to resolve the algorithm Dining philosophers step by step in the Kotlin programming language

Published on 22 June 2024 08:30 PM

How to resolve the algorithm Dining philosophers step by step in the Kotlin programming language

Table of Contents

Problem Statement

The dining philosophers problem illustrates non-composability of low-level synchronization primitives like semaphores. It is a modification of a problem posed by Edsger Dijkstra. Five philosophers, Aristotle, Kant, Spinoza, Marx, and Russell (the tasks) spend their time thinking and eating spaghetti. They eat at a round table with five individual seats. For eating each philosopher needs two forks (the resources). There are five forks on the table, one left and one right of each seat. When a philosopher cannot grab both forks it sits and waits. Eating takes random time, then the philosopher puts the forks down and leaves the dining room. After spending some random time thinking about the nature of the universe, he again becomes hungry, and the circle repeats itself. It can be observed that a straightforward solution, when forks are implemented by semaphores, is exposed to deadlock. There exist two deadlock states when all five philosophers are sitting at the table holding one fork each. One deadlock state is when each philosopher has grabbed the fork left of him, and another is when each has the fork on his right. There are many solutions of the problem, program at least one, and explain how the deadlock is prevented.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Dining philosophers step by step in the Kotlin programming language

Dining Philosophers Problem (Kotlin Version)

Overview

The "Dining Philosophers" problem is a classic in computer science used to demonstrate the challenges of concurrency and synchronization. It involves a group of philosophers sitting around a circular table with a fork on either side of each philosopher. To eat, a philosopher must acquire both forks simultaneously. If a philosopher finds that one or both forks are unavailable, they must wait until both forks are free before attempting to eat again.

Kotlin Code Explanation

The Kotlin code provided solves the Dining Philosophers problem using Reentrant Locks to ensure mutual exclusion when philosophers try to pick up forks.

Fork Class

The Fork class represents a fork on the table. It has a name and a lock that controls access to it. Philosophers must acquire the fork's lock before picking it up and release the lock when putting it down.

Philosopher Class

The Philosopher class represents a philosopher sitting at the table. Each philosopher has a name and references to the two forks left and right of them.

The run() method overrides the Thread method to define the philosopher's behavior. It contains a loop that repeats 20 times. In each iteration, the philosopher "picks up" both forks, "eats," and then "puts down" both forks.

Dining Philosophers Function

The diningPhilosophers() function creates a list of forks, a list of philosopher threads, and then starts each philosopher thread. It also waits for all philosopher threads to finish before exiting.

Main Function

The main() function initializes a list of philosopher names and calls the diningPhilosophers() function with this list. This starts the simulation of the dining philosophers problem, and the program terminates when all philosophers have finished eating.

Synchronization with Reentrant Locks

The pickUp() and putDown() methods in the Fork class use Reentrant Locks to ensure mutual exclusion when accessing the forks. This means that only one philosopher can acquire a given lock at a time, preventing multiple philosophers from picking up the same fork simultaneously.

Thread Safety

The use of locks ensures thread safety in the program. Since only one philosopher can acquire a particular fork lock at a time, there is no risk of two philosophers trying to use the same fork concurrently.

Execution

When the program runs, it creates a list of forks and a list of philosopher threads. Each philosopher thread then runs its run() method, repeatedly "eating" 20 times by acquiring and releasing the two forks it needs. The diningPhilosophers() function waits for all philosophers to finish before exiting.

Output

The output of the program shows the actions of each philosopher as they pick up and put down forks to eat. For example:

Aristotle is hungry
 Aristotle picked up Fork 1
 Aristotle picked up Fork 2
Aristotle is eating bite 1
 Aristotle put down Fork 2
 Aristotle put down Fork 1
Marx is hungry
 Marx picked up Fork 5
 Marx picked up Fork 1
Marx is eating bite 1
 Marx put down Fork 1
 Marx put down Fork 5

Source code in the kotlin programming language

// Version 1.2.31

import java.util.Random
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock

val rand = Random()

class Fork(val name: String) {
    val lock = ReentrantLock()

    fun pickUp(philosopher: String) {
        lock.lock()
        println("  $philosopher picked up $name")
    }

    fun putDown(philosopher: String) {
        lock.unlock()
        println("  $philosopher put down $name")
    }
}

class Philosopher(val pname: String, val f1: Fork, val f2: Fork) : Thread() {
    override fun run() {
        (1..20).forEach {
            println("$pname is hungry")
            f1.pickUp(pname)
            f2.pickUp(pname)
            println("$pname is eating bite $it")
            Thread.sleep(rand.nextInt(300) + 100L)
            f2.putDown(pname)
            f1.putDown(pname)
        }
    }
}

fun diningPhilosophers(names: List<String>) {
    val size = names.size
    val forks = List(size) { Fork("Fork ${it + 1}") }
    val philosophers = mutableListOf<Philosopher>()
    names.forEachIndexed { i, n ->
        var i1 = i
        var i2 = (i + 1) % size
        if (i2 < i1) {
            i1 = i2
            i2 = i
        }
        val p = Philosopher(n, forks[i1], forks[i2])
        p.start()
        philosophers.add(p)
    }
    philosophers.forEach { it.join() }
}

fun main(args: Array<String>) {
    val names = listOf("Aristotle", "Kant", "Spinoza", "Marx", "Russell")
    diningPhilosophers(names)
}


  

You may also check:How to resolve the algorithm Conditional structures step by step in the Picat programming language
You may also check:How to resolve the algorithm Command-line arguments step by step in the Nim programming language
You may also check:How to resolve the algorithm Harshad or Niven series step by step in the Befunge programming language
You may also check:How to resolve the algorithm I before E except after C step by step in the Phix programming language
You may also check:How to resolve the algorithm Sum digits of an integer step by step in the Lasso programming language