racing condition

Comprehensive study notes, diagrams, and exam preparation for racing condition.

Racing Condition

Definition

A racing condition is a condition in which the correctness of a system depends on the sequence or timing of events that occur concurrently, and a change in that timing can produce different or incorrect outcomes.

In simpler terms, if two or more execution paths race to access or change the same resource, and the final result depends on which one finishes first, a racing condition exists.

Example:

  • Thread A reads a shared counter
  • Thread B reads the same counter
  • Both increment it
  • Both write back the result

If the updates overlap without proper synchronization, one increment may be lost.


Main Content

1. First Concept: Concurrent Access to Shared Resources

  • A racing condition usually begins when multiple threads, processes, or tasks access the same shared resource at the same time.
  • The shared resource may be a variable, file, database record, buffer, memory location, hardware device, or network connection.

When concurrent operations are not coordinated, one execution may overwrite or interfere with another. This is especially dangerous when the operations involve read-modify-write behavior.

For example, suppose two users withdraw money from the same bank account simultaneously. If both read the old balance before either writes the new balance, the account may end up with the wrong amount.

Example scenario:

  • Shared variable: balance = 100
  • Thread 1 subtracts 30
  • Thread 2 subtracts 50

If both work without synchronization:

  • Thread 1 reads 100
  • Thread 2 reads 100
  • Thread 1 writes 70
  • Thread 2 writes 50

The correct final balance should be 20, but the result becomes 50 or 70 depending on timing.

Why it happens:

  • Execution order is not guaranteed
  • CPU scheduling can change at any moment
  • Interrupts may occur
  • Multiple cores may operate in parallel

2. Second Concept: Non-Deterministic Behavior

  • A key feature of a racing condition is non-determinism, meaning the output is not always the same.
  • The program may work correctly sometimes and fail at other times, which makes the problem difficult to reproduce and debug.

This unpredictability often creates the false impression that the program is stable. A program may appear correct during testing but fail under heavy load, on a different processor, or in production where timing changes.

Typical signs of non-deterministic behavior:

  • Intermittent bugs
  • Inconsistent results
  • Rare crashes
  • Missing updates
  • Unexpected output

Example: A logging system writes to the same file from multiple threads. Sometimes the lines appear correctly. Other times they are mixed together or partially overwritten because the file writes happen at nearly the same moment.

Why this is serious:

  • Bugs may be hidden during normal use
  • Reproducing the issue can be difficult
  • Small timing changes can change the entire result
  • Testing may not reveal the problem unless concurrency is stressed

3. Third Concept: Race Conditions vs. Related Problems

  • Racing condition is often confused with other concurrency issues, but it has a specific meaning.
  • It is important to distinguish it from deadlock, livelock, and data race.

Racing condition:

  • Correctness depends on timing/order
  • Can occur even if no memory corruption happens
  • Example: checking a flag before using a resource

Data race:

  • Happens when two threads access the same memory location concurrently
  • At least one access is a write
  • No proper synchronization is used
  • Often leads to undefined or incorrect behavior

Deadlock:

  • Two or more threads wait forever for each other
  • The system stops progressing
  • Example: Thread A waits for a lock held by Thread B, while Thread B waits for a lock held by Thread A

Livelock:

  • Threads keep changing state but make no progress
  • The system is active but useless

Simple illustration of a race condition:

Thread A: read x ---- increment ---- write x
Thread B:       read x ---- increment ---- write x

If both read the same old value, one update is lost.

Important idea: A racing condition is about timing-dependent correctness, while a data race is about unsynchronized memory access. They are related, but not identical.


Working / Process

1. Two or more concurrent actions begin

  • Multiple threads, processes, or events start working at about the same time.
  • They may be created by a program, triggered by interrupts, or scheduled by the operating system.

2. They access the same shared resource

  • Each action reads, modifies, or writes a common variable, file, device, or data structure.
  • If the resource is not protected, their operations can overlap.

3. The final result depends on timing

  • The order in which operations complete determines the output.
  • If the timing changes, the outcome changes too.
  • Without synchronization, one action may overwrite another, use stale data, or make a decision based on outdated information.

Example process in a shared counter:

  1. Counter starts at 10
  2. Thread A reads 10
  3. Thread B reads 10
  4. Thread A adds 1 and writes 11
  5. Thread B adds 1 and writes 11

Expected result: 12
Actual result: 11

This happens because both threads followed the same sequence, but the order of their execution caused one update to be lost.


Advantages / Applications

Helps identify concurrency bugs

  • Understanding racing conditions makes it easier to find hidden problems in multithreaded programs and shared systems.

Improves program reliability

  • Once detected, they can be prevented using locks, semaphores, atomic operations, or other synchronization methods.

Important in real-world systems

  • They are relevant in operating systems, banking software, web servers, databases, embedded devices, and networked applications where multiple operations happen at once.

Summary

  • Racing condition is a timing-dependent problem in concurrent execution.
  • It occurs when shared resources are accessed without proper coordination.
  • Its effects are often unpredictable and difficult to reproduce.
  • Important terms to remember: shared resource, concurrency, timing, non-determinism, synchronization