Most such resources are the fine-grained flags, counters, queues and other data used to communicate between code that runs on an interrupts, and code that runs the rest of the time. The problem is acute because without special care, an interrupt can occur between any two instructions of the non-interrupt code, including especially the very code used to communicate with the interrupt code. If the critical section is not protected, this causes failure.
The standard way to achieve mutual exclusion is to disable interrupts for the smallest possible number of instructions that will prevent corruption of the shared data structure, the so-called "critical region." This prevents interrupt code from running in the critical region.
In a computer in which several processors share memory, an indivisible test-and-set of a flag is used in a tight loop to wait until the other computer clears the flag. The test-and-set performs both operations without releasing the memory bus to another processor. When the code leaves the critical region, it clears the flag. This is called a "spin lock" or "busy-wait."
Some computers have similar indivisible multiple-operation instructions for manipulating the linked lists used for event queues and other data structures commonly used in operating systems.
Most classical mutual exclusion methods attempt to reduce latency and busy-waits by using queuing and context switches. Some persons claim that benchmarks indicate that these special algorithms waste more time than they save.
Many forms of mutual exclusion have side-effects. For example, classic semaphores permit deadlocks, in which one process gets a semaphore, another process gets a semaphore, and then both wait forever for the other semaphore to be released. Other common side-effects include "starvation," in which an essential process does not run enough, and "priority inversion" in which a higher priority task waits for a lower-priority task, and "high latency" in which response to interrupts is not prompt.
Much research attempts to eliminate the above effects. No perfect scheme is known. One intriguing non-classical scheme sends messages between pieces of code. This permits priority inversions, and increases latency but makes deadlocks unlikely.
Examples of classical mutex algorithms include:
See also: