How a race condition loses an update

A program can appear to perform one simple change while actually taking several steps. To add 1 to a shared counter, for example, it may read the current value, calculate a new one, then write it back. If two processes read 10 before either writes, each calculates 11. Both store 11, so the counter rises by one instead of two. The final result depends on the timing of the steps—a problem called a race condition.

This can happen even when each process is correct on its own. The danger is that their operations overlap, splitting a change that was meant to act as one indivisible unit. Similar timing issues can affect inventory, account balances, or records edited by multiple requests.

Making the change indivisible

Programs prevent these conflicts by coordinating access to shared data. A lock lets one process enter a sensitive section at a time; others wait until it finishes. For simple operations, an atomic instruction performs the read-and-update as one indivisible action. Databases offer transactions, which group related changes so they succeed together or are rolled back.

Coordination has a cost: waiting can slow work, and poorly managed locks can make processes block one another. The design challenge is to protect changes that must stay consistent without unnecessarily serializing everything. A tiny timing window can determine whether a system records both updates—or silently drops one.