A good example of deadlock is the dining philosophers problem. In this problem, there are n philosophers trying to have dinner with n chopsticks. Each requires two chopsticks to eat. How can we allocate the chopsticks such that every philosopher gets to eat?
From wikipedia:
In an operating system, a deadlock occurs when a process or thread enters a waiting state because a requested system resource is held by another waiting process, which in turn is waiting for another resource held by another waiting process.
We can model resource allocation by having resources and processes represented as vertices and use edges to show ownership of a resource. A cycle in the (undirected) resource allocation graph implies that we have deadlock.
Have one authority (e.g. a mutex). Have each philosopher grab that authority and only when they have the authority can they pick up their forks and eat. They eat, put the arbitrator and the forks down and move on to the next philosopher (can be random or sequential).
Consider the case of the dining philosophers with n-chopsticks and n-philosophers. Reduce the number of philosophers currently allowed at the table to n-1 using a semaphore. Have them eat. Cycle out the philosophers.
Order the chopsticks 1..n. For each philosopher have them pick up the lower number chopstick. Then, only if they can pick up the lower chopstick, pick up the higher chopstick. Why does this work?
If you want reeealllllllly fast (given a lot of philosophers numbered 1..n).
Chopsticks can be dirty or clean. Initially all chopsticks start out as dirty. For each pair of philosophers, assign the chopstick between them to the philosopher with the lower id. When a philosopher wants to eat, they ask the person next to them for a chopstick. If the neighbor’s chopstick is clean (they haven’t eaten yet), they keep the chopstick. Otherwise, they clean it, and give it to the requesting philosopher. This prevents starvation of philosophers and ensures priority is given to the philosopher that has least recently eaten.