Skip to main content

Overview

The Race Checkpoint scenario simulates runners in a race who must all reach a checkpoint before any can continue to the finish line. This demonstrates the use of barriers for synchronizing multiple threads at a rendezvous point.

Real-World Problem

Imagine a relay race or team challenge where:
  • Multiple runners start at different times
  • All must reach a checkpoint before any can continue
  • The slowest runner determines when everyone proceeds
  • Once all arrive, everyone continues simultaneously to the finish
This requires a synchronization primitive where threads wait until all participants reach a common point.

Shared Resources

The shared resource is a barrier object that tracks:
  • Total number of expected participants
  • Count of threads that have reached the barrier
  • Whether all threads have synchronized
Protected by: Barrier (synchronization primitive)

Synchronization Algorithm

This scenario uses a Barrier for rendezvous synchronization:
1

Race to Checkpoint

Each racer thread runs at its own pace toward the checkpoint
2

Reach Barrier

When a racer reaches the checkpoint, it calls wait() on the barrier
3

Wait for Others

The racer blocks until all other racers reach the barrier
4

Release All

When the last racer arrives, the barrier releases all waiting threads simultaneously
5

Continue to Finish

All racers proceed together from checkpoint to finish line

Scenario Setup

raceBarrierScenario.js
import { Thread } from "../core/thread.js";
import { Instructions } from "../core/instructions.js";
import { Barrier } from "../core/barrier.js";

export function createRaceBarrierScenario(engine, racerCount) {
  const safeRacers = Math.max(1, Number(racerCount) || 1);
  const barrier = new Barrier(safeRacers);

  const race = {
    barrier,
    totalRacers: safeRacers,
    passedCheckpointCount: 0,
    finishedCount: 0,
  };

  for (let i = 1; i <= safeRacers; i++) {
    const instructions = [
      { type: Instructions.RUN_STAGE, stage: "to-checkpoint" },
      { type: Instructions.BARRIER_WAIT },
      { type: Instructions.RUN_STAGE, stage: "to-finish" },
      { type: Instructions.END },
    ];

    const racer = new Thread(`Corredor-${i}`, instructions);
    racer.role = "racer";
    racer.passedCheckpoint = false;
    racer.finishedRace = false;
    engine.addThread(racer);
  }

  return { race };
}

Configuration Options

ParameterDescriptionDefault
racerCountNumber of racer threadsMinimum 1
The barrier must be initialized with the exact number of expected participants. If the count is wrong, threads may wait forever (if too high) or the barrier may release prematurely (if too low).

Example Execution Flow

Barrier Count: 4

Time 0:
  Corredor-1: RUN_STAGE "to-checkpoint" (fast)
  Corredor-2: RUN_STAGE "to-checkpoint" (medium)
  Corredor-3: RUN_STAGE "to-checkpoint" (slow)
  Corredor-4: RUN_STAGE "to-checkpoint" (medium)

Time 2:
  Corredor-1: Reaches checkpoint → BARRIER_WAIT
    Barrier: 1/4 arrived → BLOCK Corredor-1

Time 4:
  Corredor-2: Reaches checkpoint → BARRIER_WAIT
    Barrier: 2/4 arrived → BLOCK Corredor-2
  Corredor-4: Reaches checkpoint → BARRIER_WAIT
    Barrier: 3/4 arrived → BLOCK Corredor-4

Time 7:
  Corredor-3: Reaches checkpoint → BARRIER_WAIT
    Barrier: 4/4 arrived → RELEASE ALL!

Time 8:
  Corredor-1: UNBLOCKED → RUN_STAGE "to-finish"
  Corredor-2: UNBLOCKED → RUN_STAGE "to-finish"
  Corredor-3: UNBLOCKED → RUN_STAGE "to-finish"
  Corredor-4: UNBLOCKED → RUN_STAGE "to-finish"

Time 12:
  All racers: END

Thread Instructions

Each racer thread executes:
  1. RUN_STAGE (to-checkpoint) - Run from start to checkpoint at thread’s pace
  2. BARRIER_WAIT - Wait at checkpoint until all racers arrive
  3. RUN_STAGE (to-finish) - Run from checkpoint to finish line
  4. END - Complete the race

Barrier Properties

All-or-Nothing Synchronization

Either all threads wait, or all threads proceed
No thread advances past the barrier alone

Reusability

Barriers can be reused for multiple synchronization points
(Implementation-dependent)

Deadlock Risk

If barrier count > actual threads, remaining threads wait forever
Critical: Initialize with correct participant count

Use Cases

ScenarioDescription
Parallel AlgorithmsSynchronize phases in parallel computation
SimulationEnsure all actors complete a time step before advancing
TestingCoordinate threads to trigger race conditions
GamesWait for all players ready before starting match
Data ProcessingComplete one stage before starting the next

Comparison with Other Primitives

PrimitivePurposeWaiting
MutexMutual exclusionOne thread proceeds
SemaphoreResource countingN threads proceed
BarrierRendezvous pointAll threads wait, then all proceed
Condition VariableWait for conditionSelective wakeup

Key Learning Points

  • Rendezvous Synchronization: All threads meet at a common point
  • Bulk Release: When the last thread arrives, all are released simultaneously
  • No Priority: The slowest thread determines when everyone proceeds
  • Phase Synchronization: Useful for multi-phase parallel algorithms
  • Count Accuracy: Barrier count must match actual thread count

Common Patterns

for each iteration:
  do_work()
  barrier.wait()  // Sync before next iteration