Skip to main content

Race Condition

Updated 3 min read

Share this page

Send the link, quote the definition with a link back, or show it as a card on your own site.

https://softwaredictionary.org/terms/race-condition

In short

A race condition is a bug where a program's result depends on the unpredictable timing of threads, processes, or requests that use shared data at the same time.

What is a race condition?

A race condition happens when two or more operations run concurrently, touch the same data or resource, and at least one of them changes it, so the result depends on which one happens to go first. Because the timing changes from run to run, the program may work correctly thousands of times and then fail once, which makes race conditions some of the hardest bugs to reproduce.

The classic case is counter += 1, which is really three steps: read the value, add one, and write it back. If two threads both read 5, both write 6, and one increment is lost. Another common pattern is check-then-act, such as checking that a file doesn't exist and then creating it, while another process creates it in between; this is called time-of-check to time-of-use (TOCTOU) and is also a well-known class of security vulnerability. Races are not limited to threads: two web requests buying the last concert ticket, or two processes writing the same file, can race too.

Imagine two people sharing a bank account who check the balance of $100 at two ATMs at the same moment. Both see enough money, both withdraw $80, and without coordination the bank lets both happen. Fixes include mutexes and other locks, atomic operations, database transactions with a suitable isolation level or optimistic locking, and designs that avoid shared mutable state, such as immutable data or message passing. Tools such as thread sanitizers and Go's race detector help find races during testing.

Race conditions are often mixed up with deadlocks. With a race condition the program keeps running but produces wrong results; with a deadlock it stops making progress. The two are linked, because adding locks to fix a race can create a deadlock if they are acquired in inconsistent orders. Mutexes and semaphores are the tools; the race condition is the bug they prevent.

At a glance

Two threads both read counter = 5 before either writes, both compute 5 + 1 and both write 6, so the counter ends at 6 instead of 7.Thread 1counterThread 21reads 52reads 53writes 64writes 65 + 15 + 1counter = 6expected 7
Read, add one and write back are three separate steps. When two threads interleave them, one increment is lost.

Key takeaways

  • A race condition makes the outcome depend on the timing of concurrent operations.
  • Read-modify-write and check-then-act sequences are the most common causes.
  • Races can happen between threads, processes, or separate web requests.
  • Locks, atomic operations, and transactions are the usual fixes.
  • A race gives wrong results, while a deadlock stops progress entirely.

Example

A race between two async requests in JavaScriptjavascript
// Two requests try to buy the last ticket at the same time
async function buyTicket(userId) {
  const event = await db.getEvent(1);  // both requests read seatsLeft = 1
  if (event.seatsLeft > 0) {           // both pass the check...
    await db.createOrder(userId);
    await db.updateEvent(1, { seatsLeft: event.seatsLeft - 1 });
  }
}
await Promise.all([buyTicket("ada"), buyTicket("linus")]); // 2 orders, 1 seat

// Fix: make the check and the update one atomic step in the database:
// UPDATE events SET seats_left = seats_left - 1
//   WHERE id = 1 AND seats_left > 0
// ...and create the order only if exactly one row was updated.

Readers ask

What is the difference between a race condition and a deadlock?

A race condition lets the program keep running but can corrupt data or produce wrong results. A deadlock freezes the threads involved because each waits for a resource another one holds.

Can race conditions happen in single-threaded JavaScript?

Yes. Code never runs in parallel on one thread, but every await lets other tasks run in between, so two async operations can still interleave around shared data or an external database.

What is the difference between a data race and a race condition?

A data race is a specific low-level case: two threads access the same memory at the same time without synchronization, and at least one writes. A race condition is the broader problem of timing-dependent results, and it can exist even when every individual access is properly synchronized.

See also

Spotted a mistake or something missing on this page?Suggest an edit

Read a random page
Open today's review
Switch to the dark theme
Read this page in Türkçe

More

Settings