A situation in which several entities (e.g. processes) wait in a circular fashion for each other. Each entity waits for a resource
held by another entity which will never be freed because that entity again waits for a resource held by yet another entity until the loop
is closed. Instead for waiting on resources the entities could also
wait for actions of another entity. You can imagine it as 4 cars reaching at the same time an intersection with a "give way to right"-rule.
More technically there are four preconditions for a deadlock to
occur:
Mutual Exclusion: Each resource can only be used by
one entity. (More generally: by a fixed number of entities. If a
resource can be used by e.g. three entities at the same time, it can
still be modeled with mutual exclusion by splitting it up into
three resources .)
Wait and Hold: Entities which wait for a resource hold
on to the resources they have already allocated.
No preemption: None of the allocated resources can be
withdrawn from an entity by another.
Circular wait: The waiting graph forms a circle.
There are three things one can do against deadlocks: First, design
your system so that at least one of the above preconditions does not
hold. This is called deadlock prevention. If no deadlock prevention
is there but the resource allocation algorithm uses a strategy to
hand out resources that always keeps the system in a deadlock-safe
state, it is called deadlock avoidance. The algorithm every computer
scientist has to learn is Dijkstra's Banker's Algorithm. If neither of
the two is there but the system is monitoring its entities and e.g.
kills one of those in a deadlock circle, it is called deadlock detection (and resolution). Each of these solutions becomes more
difficult in a distributed system.