Why a Shared Counter Can Lose an Update

A line such as `count++` looks like one operation, but a processor typically performs it in steps: read the value, add one, then write the result back. If two threads do those steps at nearly the same time, both may read 7 and both write 8. One increment disappears. This timing-dependent bug is called a race condition.

A mutex—short for “mutual exclusion”—protects the whole sequence, not just the final write. A thread must acquire the lock before entering the code that touches shared state, then release it when finished. If another thread reaches the same protected code meanwhile, it waits; once the lock is free, it can proceed using the updated value.

The Boundary Is the Programmer’s Responsibility

The lock works only if every thread follows the same rule. If one path reads or changes the variable without acquiring the mutex, the protection is incomplete. The protected region, often called a critical section, should therefore cover all operations that need to behave as one coordinated action—but not unrelated work.

That boundary matters for performance. While one thread holds the lock, others cannot do useful work in that section, even if the processor has spare capacity. A lock held briefly around a shared update may be a small cost; a lock held while doing slow work can turn a busy program into a queue.

Locks also introduce a coordination hazard: if threads acquire multiple mutexes in different orders, each can end up waiting for a lock held by the other. Neither can continue. This is a deadlock, and it shows why adding a mutex is not merely a matter of making access safe. The code must also make the order and duration of that access predictable.