Race Conditions, Locks, and Deadlocks

Problem

Two workers update an application's shared counter. Both read 40, both add one, and both write 41. Two requests finished, but the counter increased only once. The bug disappears when you test one request at a time.

Solution — Synchronization

This is a race condition: correctness depends on how operations overlap. Reading, changing, and writing a value is not necessarily one indivisible operation. A mutex, or mutual-exclusion lock, lets one participant at a time enter a protected section. If every worker uses the same lock around the complete update, the second worker sees 41 and writes 42. A supported atomic increment can solve this particular case more directly. A semaphore manages a number of permits. Ten permits can limit a resource to ten concurrent users; each user returns its permit when finished. Locks introduce their own risk. If worker A holds lock X and waits for Y, while worker B holds Y and waits for X, neither can proceed: a deadlock. Keep protected sections short, acquire multiple locks in a consistent order, and release them even when an operation fails. A lock inside one application instance does not coordinate other instances.
Core idea: shared mutable state needs coordination that protects the whole operation and reaches every participant.