Skip to main content

Overview

The House Construction scenario simulates building a house with multiple workers where some tasks depend on others being completed first. This demonstrates thread join and await operations for managing task dependencies in concurrent programs.

Real-World Problem

Building a house has natural dependencies:
  • Walls cannot be built until the foundation is complete
  • The roof requires walls to be finished first
  • Installations (plumbing, electrical) need walls but not the roof
  • The architect can only deliver the house when both roof and installations are done
Workers should start their tasks as soon as dependencies are met, not before.

Shared Resources

The shared resource is a house state object tracking:
  • Progress for each construction stage (foundation, walls, roof, installations)
  • Which worker owns each stage
  • Completion status of each stage
  • Overall house delivery status
Coordinated by: Join Manager (tracks thread completion for dependencies)

Synchronization Algorithm

This scenario uses Join and Await operations:
1

Foundation Starts Immediately

Foundation worker begins work with no dependencies
2

Dependent Tasks Join

Wall worker executes JOIN_THREAD on foundation worker, blocking until foundation completes
3

Parallel Dependent Tasks

Once walls complete, both roof worker and installation worker can proceed in parallel
4

Architect Awaits Multiple Threads

Architect executes AWAIT_ALL on roof and installation workers, blocking until both finish
5

House Delivery

Once all dependencies met, architect completes the house

Scenario Setup

houseScenario.js
import { Thread } from "../core/thread.js";
import { Instructions } from "../core/instructions.js";
import { JoinManager } from "../core/joinManager.js";

export function createHouseScenario(engine, durations) {
  const d = {
    foundation: Math.max(1, Number(durations.foundation) || 1),
    walls: Math.max(1, Number(durations.walls) || 1),
    roof: Math.max(1, Number(durations.roof) || 1),
    installations: Math.max(1, Number(durations.installations) || 1),
  };

  const house = {
    delivered: false,
    stages: {
      Cimientos: { current: 0, total: d.foundation, owner: "Maestro-Cimientos", done: false },
      Paredes: { current: 0, total: d.walls, owner: "Maestro-Paredes", done: false },
      Techo: { current: 0, total: d.roof, owner: "Techador", done: false },
      Instalaciones: {
        current: 0,
        total: d.installations,
        owner: "Instalador",
        done: false,
      },
    },
  };

  const joinManager = new JoinManager();

  // 1) Foundation: no dependencies
  const foundationWorker = new Thread("Maestro-Cimientos", [
    { type: Instructions.BUILD_STAGE, stage: "Cimientos", duration: d.foundation },
    { type: Instructions.END },
  ]);

  // 2) Walls: depends on foundation
  const wallWorker = new Thread("Maestro-Paredes", [
    { type: Instructions.JOIN_THREAD, target: "Maestro-Cimientos" },
    { type: Instructions.BUILD_STAGE, stage: "Paredes", duration: d.walls },
    { type: Instructions.END },
  ]);

  // 3) Roof: depends on walls
  const roofWorker = new Thread("Techador", [
    { type: Instructions.JOIN_THREAD, target: "Maestro-Paredes" },
    { type: Instructions.BUILD_STAGE, stage: "Techo", duration: d.roof },
    { type: Instructions.END },
  ]);

  // 4) Installations: depends on walls
  const installationWorker = new Thread("Instalador", [
    { type: Instructions.JOIN_THREAD, target: "Maestro-Paredes" },
    { type: Instructions.BUILD_STAGE, stage: "Instalaciones", duration: d.installations },
    { type: Instructions.END },
  ]);

  // 5) Architect: awaits roof + installations
  const architect = new Thread("Arquitecto", [
    { type: Instructions.AWAIT_ALL, targets: ["Techador", "Instalador"] },
    { type: Instructions.COMPLETE_HOUSE },
    { type: Instructions.END },
  ]);

  engine.addThread(foundationWorker);
  engine.addThread(wallWorker);
  engine.addThread(roofWorker);
  engine.addThread(installationWorker);
  engine.addThread(architect);

  return { house, joinManager, architectThread: architect };
}

Configuration Options

ParameterDescriptionDefault
durations.foundationCycles to build foundationMinimum 1
durations.wallsCycles to build wallsMinimum 1
durations.roofCycles to build roofMinimum 1
durations.installationsCycles for installationsMinimum 1

Dependency Graph

           Foundation
               |
               v
            Walls
            /    \
           /      \
          v        v
        Roof    Installations
           \      /
            \    /
             v  v
          Architect
             |
             v
       House Complete

Example Execution Flow

Time 0:
  Maestro-Cimientos: START BUILD_STAGE "Cimientos"
  Maestro-Paredes: JOIN "Maestro-Cimientos" → BLOCKED
  Techador: JOIN "Maestro-Paredes" → BLOCKED
  Instalador: JOIN "Maestro-Paredes" → BLOCKED
  Arquitecto: AWAIT_ALL [Techador, Instalador] → BLOCKED

Time 3:
  Maestro-Cimientos: COMPLETE "Cimientos" → END
  Maestro-Paredes: UNBLOCKED → START BUILD_STAGE "Paredes"

Time 7:
  Maestro-Paredes: COMPLETE "Paredes" → END
  Techador: UNBLOCKED → START BUILD_STAGE "Techo"
  Instalador: UNBLOCKED → START BUILD_STAGE "Instalaciones"
  (Roof and Installations proceed in parallel)

Time 9:
  Techador: COMPLETE "Techo" → END
  Arquitecto: Still waiting for Instalador

Time 10:
  Instalador: COMPLETE "Instalaciones" → END
  Arquitecto: UNBLOCKED → COMPLETE_HOUSE
  House delivered! 🏠

Total Time: 10 cycles

Thread Instructions

Workers with dependencies:
  1. JOIN_THREAD - Block until specified thread completes
  2. BUILD_STAGE - Perform construction work for this stage
  3. END - Thread terminates
Architect with multiple dependencies:
  1. AWAIT_ALL - Block until all specified threads complete
  2. COMPLETE_HOUSE - Finalize and deliver the house
  3. END - Thread terminates
Join blocks one thread until another completes. Await blocks until multiple threads complete. Both enable expressing task dependencies without busy-waiting.

Join vs Await

OperationSyntaxWaits For
JOIN_THREADJOIN_THREAD(target)Single thread to complete
AWAIT_ALLAWAIT_ALL([t1, t2, ...])Multiple threads to complete

Parallelism Opportunities

Sequential Stages: Foundation → Walls
Total: 3 + 4 = 7 cycles

Parallel Stages: Roof ‖ Installations
Total: max(2, 3) = 3 cycles (not 5!)

Overall: 7 + 3 = 10 cycles
(vs 12 cycles if all sequential)

Key Learning Points

  • Task Dependencies: Some tasks must complete before others can start
  • Join Operation: Wait for a single thread to complete
  • Await Operation: Wait for multiple threads to complete
  • Parallelism: Independent tasks (roof + installations) run concurrently
  • Critical Path: Longest dependency chain determines total time
  • Coordination: JoinManager tracks thread completion for dependent threads

Common Patterns

// Task B must wait for Task A
threadA.start();
threadB.join(threadA);  // Wait for A
threadB.start();

Comparison with Other Primitives

PrimitivePurposeWhen to Use
JoinWait for thread completionTask dependencies
BarrierSynchronize at checkpointIterative phases
MutexMutual exclusionProtect shared data
SemaphoreResource countingLimited resources
Condition VariableWait for conditionProducer-consumer

Optimization Considerations

To minimize total construction time:
  • Identify the critical path (longest dependency chain)
  • Maximize parallelism for independent tasks
  • Balance workload across parallel tasks
  • Minimize idle time for expensive resources