Fetch-and-add
From Wikipedia, the free encyclopedia
In computer science, the fetch-and-add CPU instruction is a special instruction that atomically modifies the contents of a memory location. It is used to implement Mutual exclusion and concurrent algorithms in multiprocessor systems.
In uniprocessor systems, it is sufficient to disable interrupts before accessing a critical region. However, in multiprocessor systems, it is impossible and undesirable to disable interrupts on all processors at the same time; and even with interrupts disabled two or more processors could be attempting to access the same memory at the same time. The fetch-and-add instruction, allows any processor to atomically increment a value in memory location, preventing such multiple processor collisions.
Maurice Herlihy (1993) proved that fetch-and-add is inferior to compare-and-swap.
[edit] Implementation
The standard fetch and add -instruction behaves like the following function. Crucially the entire function is executed atomically: no process can interrupt the function mid-execution and hence see a state that only exists during the execution of the function. This code only serves to help explain the behaviour of fetch-and-add, atomicity requires explicit hardware support and hence can not be implemented as a simple high level function.
<< atomic >> function FetchAndAdd(address location) { int value := *location *location := value + 1 return value }
With fetch-and-add primitive a mutual exclusion lock can be implemented as:
record locktype { int ticketnumber int turn } procedure LockInit( locktype* lock ) { lock.ticketnumber := 0 lock.turn := 0 } procedure Lock( locktype* lock ) { int myturn := FetchAndAdd( &lock.ticketnumber ) while lock.turn ≠ myturn skip // spin until lock is acquired } procedure UnLock( locktype* lock) { FetchAndAdd( &lock.turn ) }
These routines provide a mutual exclusion lock when following conditions are met:
- Locktype data structure is initialized with function LockInit before use
- Number of tasks waiting for the lock does not exceed INT_MAX at any time
- Integer datatype used in lock values can 'wrap around' when continuously incremented