Python 3 solution - Explaining deadlocks
Intuition\nMy first intuition was to create the 5 locks to share between the indexes, getting left and right and acquire/release them. But this solution didn\'t
# Intuition\nMy first intuition was to create the 5 locks to share between the indexes, getting left and right and acquire/release them. But this solution didn\'t work and I was a bit puzzled of what was going on.\n\nThis is because this problem is teaching about deadlocks. How to identify or avoid them.\n\nThis solution is the same as many others here, but I had troubles understanding deadlocks so I created some images that helped me understand it better.\n# Approach\n<!-- Describe your approach to solving the problem. -->\nThe main problem is that when we execute all the processes at the same time, they block each other (definition of deadlock).\n\nIn the next image, each row is a process (a philosopher trying to eat). And all of them start at the same time.\n\n![Untitled-2024-04-15-0634.png](https://assets.leetcode.com/users/images/fd6dd417-4718-4cce-945d-adf63df1e1a3_1713164988.2573276.png)\n\nAs you can see, in t1, everyone is happy with their locks (forks), but at T2, they try to get the other one and they\'re completely blocked.\n\nWhat happens if, instead, the first process takes the locks in a different order?\n\n![Untitled-2024-04-15-0634(1).png](https://assets.leetcode.com/users/images/d739f5ee-4ac5-4ae7-b4b6-9fcb8b159a3b_1713165164.7844434.png)\n\nAt T1, everyone but the 2nd process got their locks, and then at T2, the first process can take the other lock, allowing it to continue with the execution.\n\nOnce they\'re done, the rest of the processes can execute properly.\n\nHope this helped you understand it better! :D\n\n# Code\n```\nimport threading\n\nclass DiningPhilosophers:\n\n    def __init__(self):\n        self.locks = [threading.Lock() for _ in range(5)]\n\n    # call the functions directly to execute, for example, eat()\n    def wantsToEat(self,\n                   philosopher: int,\n                   pickLeftFork: \'Callable[[], None]\',\n                   pickRightFork: \'Callable[[], None]\',\n                   eat: \'Callable[[], None]\',\n                   putLeftFork: \'Callable[[], None]\',\n                   putRightFork: \'Callable[[], None]\') -> None:\n        if philosopher == 0:\n            right = philosopher\n            left = (philosopher + 1) % 5\n        else:\n            left = philosopher\n            right = (philosopher + 1) % 5\n        \n        with self.locks[left], self.locks[right]:\n            pickLeftFork()\n            pickRightFork()\n            eat()\n            putLeftFork()\n            putRightFork()\n\n\n```
['Concurrency', 'Python3']