Skip to main content

Overview

The Bank Account scenario simulates multiple clients performing concurrent transactions (deposits and withdrawals) on a shared bank account. This demonstrates the classic race condition problem where unsynchronized access to shared resources can lead to incorrect balances.

Real-World Problem

Imagine a bank account that multiple clients can access simultaneously:
  • Multiple ATMs processing transactions
  • Online banking operations happening concurrently
  • Mobile app transactions overlapping with web transactions
Without proper synchronization, two clients reading the balance at the same time, performing calculations, and writing back could result in lost updates.

Shared Resources

The shared resource is a bank account object containing a balance property that all client threads access and modify.
Protected by: Mutex (Mutual Exclusion Lock)

Synchronization Algorithm

This scenario uses a Mutex to ensure that only one client can access the account at a time:
1

Acquire the Lock

Client thread requests exclusive access to the account by acquiring the mutex
2

Perform Transaction

Client safely reads the balance, performs the operation (deposit/withdrawal), and updates the balance
3

Release the Lock

Client releases the mutex, allowing other waiting clients to proceed

Scenario Setup

bankScenario.js
import { Thread } from "../core/thread.js";
import { Instructions } from "../core/instructions.js";
import { Mutex } from "../core/mutex.js";

export function createBankScenario(
  engine,
  threadCount,
  operations,
  initialBalance,
) {
  const mutex = new Mutex();
  const account = { balance: initialBalance };

  for (let i = 1; i <= threadCount; i++) {
    const operation = operations[i - 1] ?? {
      type: Instructions.WITHDRAW,
      amount: 100,
    };
    const amount = Math.max(0, Number(operation.amount) || 0);

    const instructions = [
      { type: Instructions.ACQUIRE },
      { type: operation.type, amount },
      { type: Instructions.RELEASE },
      { type: Instructions.END },
    ];

    const thread = new Thread(`Cliente-${i}`, instructions);
    engine.addThread(thread);
  }

  return { mutex, account };
}

Configuration Options

ParameterDescriptionDefault
threadCountNumber of client threadsVaries
operationsArray of operations (type + amount)Withdrawals of 100
initialBalanceStarting account balanceVaries

Example Execution Flow

Initial Balance: 1000

Client-1: ACQUIRE → WITHDRAW 200 → RELEASE
  Balance: 1000 → 800

Client-2: ACQUIRE → DEPOSIT 150 → RELEASE
  Balance: 800 → 950

Client-3: ACQUIRE → WITHDRAW 100 → RELEASE
  Balance: 950 → 850

Final Balance: 850 ✓

Thread Instructions

Each client thread executes the following instruction sequence:
  1. ACQUIRE - Request mutex lock
  2. WITHDRAW or DEPOSIT - Perform the transaction with specified amount
  3. RELEASE - Release mutex lock
  4. END - Terminate thread
The mutex ensures mutual exclusion: while one client holds the lock, all other clients must wait, preventing race conditions and ensuring account balance consistency.

Key Learning Points

  • Critical Section: The code between ACQUIRE and RELEASE is the critical section
  • Race Condition: Without the mutex, concurrent operations lead to incorrect balances
  • Mutual Exclusion: Only one thread can hold the mutex at any time
  • Atomicity: Each transaction appears to execute atomically from other threads’ perspective