1

I was tasked with providing my own solution to the dining philosophers problem in Python 3. The code below is my solution. For the most part it works as I expect it to, so I assume I'm reasonably close.

import time
import threading
from concurrent.futures import ThreadPoolExecutor
    
class forks:
    lock = threading.RLock()
    fork_available = []

    def __init__(self):
        for i in range(5):
            self.fork_available.append(True)

class phil:
    def __init__(self, name, num, fork_instance):
        self.name = name
        self.num = num
        self.forks_instance = forks_instance

    def behaviour(self):
        while True:
            print(f'{self.name} is thinking\n')
            time.sleep(2)
            print(f'{self.name} is hungry, reaching for the forks:\n')
            with forks_instance.lock:
                if self.forks_instance.fork_available[self.num] is True and self.forks_instance.fork_available[
                    (self.num + 1) % 5] is True:
                    self.forks_instance.fork_available[self.num] = False
                    self.forks_instance.fork_available[(self.num + 1) % 5] = False
                    print(f'{self.name} is eating\n')
                    time.sleep(3)
                    print(f'{self.name} is done, putting down forks\n')
                    self.forks_instance.fork_available[self.num] = True
                    self.forks_instance.fork_available[(self.num + 1) % 5] = True


if __name__ == '__main__':
    forks_instance = forks()
    with ThreadPoolExecutor(max_workers=5) as ex:
        p = [phil('Platon', 1, forks_instance), phil('Larry', 2, forks_instance), phil('Mark', 3, forks_instance),
             phil('Victor', 4, forks_instance), phil('Musa', 5, forks_instance)]
        for person in p:
            ex.submit(person.behaviour)

However, one of the problems is that the last person - in this case Musa - doesn't try to reach for the forks or eat. I am positive it actually is being deployed by the executor as the program always starts with this:

Platon is thinking
Larry is thinking
Mark is thinking
Victor is thinking
Musa is thinking

But after that, the last thread does nothing.

Another problem I encountered, although it's a minor one is that the console sometimes skips newline:

Larry is hungry, reaching for the forks:Victor is hungry, reaching for the forks:Mark is hungry, reaching for the 

Although it sometimes gets it right:

Victor is hungry, reaching for the forks:
Larry is done, putting down forks
Larry is thinking
Mark is eating

Any help with solving these 2 issues is appreciated.

I'm aware this problem has many solutions online including Python, although I've been unable to find one in Python 3. Also considering I'm close I'd really like to get my approach to work.

Community
  • 1
  • 1
  • 1
    As per this SO thread printing to stdout is not thread-safe. That may be the cause of your newline missing. https://stackoverflow.com/questions/7687862/why-a-script-that-uses-threads-prints-extra-lines-occasionally – fzn Nov 15 '19 at 09:07

1 Answers1

1

In your code self.forks_instance.fork_available[self.num] will throw list index out of range exception for Musa.

self.num for this person is 5. However your self.fork_available array will have indexes 0, 1, 2, 3, 4. The Musa thread is silently crashing on this uncaught error.

Easy fix would be to change Musa's num value to 0:

p = [phil('Platon', 1, forks_instance), phil('Larry', 2, forks_instance), phil('Mark', 3, forks_instance),
     phil('Victor', 4, forks_instance), phil('Musa', 0, forks_instance)]
fzn
  • 514
  • 3
  • 10