Skip to content

llukito/multithreaded-banking-system

Repository files navigation

High-Concurrency Banking Ledger

Language Concurrency Status

A high-performance banking simulation engine implemented in C, designed to handle massive parallel transaction loads. This project demonstrates advanced systems programming concepts, focusing on thread safety, deadlock prevention, and race condition elimination in a shared-memory environment.

Key Features

  • Fine-Grained Concurrency: Implements individual mutex locks for every Account and Branch (rather than a single global lock), maximizing throughput by allowing non-conflicting transactions to proceed in parallel.
  • Deadlock Prevention: Enforces a strict hierarchical locking protocol (Lock Order: Branch ID -> Account ID) to mathematically eliminate circular wait conditions.
  • Atomic Transactions: Guarantees ACID-like properties for cross-branch transfers. Money is never "lost" or "duplicated" in flight, even if context switches occur mid-transaction.
  • Custom Synchronization Primitives: Features a custom barrier implementation using Condition Variables (pthread_cond) to synchronize worker threads for end-of-day reporting.

Technical Engineering Challenges

1. The Atomicity Gap & Race Conditions

In naive implementations, checking a balance and updating it are separate instructions. In a multithreaded environment, a context switch between these steps leads to "dirty reads" and inconsistent global states. Solution: Designed a "Branch-First" locking strategy. The worker thread acquires all necessary locks (Source Branch, Dest Branch, Source Account, Dest Account) before executing any logic, ensuring the transaction is atomic and isolated.

2. 64-bit Architecture & Memory Alignment

During development, implicit function declarations caused 64-bit account IDs to be truncated to 32 bits during bit-shifting operations, leading to memory addressing errors. Solution: Enforced strict function prototyping and utilized manual bit-shifting with uint64_t casting to guarantee correct memory addressing across different system architectures.

3. Verification with Helgrind

The system was rigorously stress-tested using Valgrind's Helgrind tool. Result: 0 Data Races, 0 Deadlocks, and 0 Lock Order Violations under heavy load (16+ concurrent threads).

Compilation & Usage

Build

To compile the multi-threaded engine:

make

Running the Engine

The simulation runs via the command-line interface, allowing users to configure worker thread counts and stress-test parameters.

./bank_engine -t[TEST_ID] -w[WORKER_COUNT] [OPTIONS]

Configuration Flags

  • -wN: Sets the number of concurrent worker threads (Tellers).
    • Example: -w16 runs the simulation with 16 parallel threads.
  • -tN: Selects the workload scenario (varying branch/account topology).
  • -r: Race-checker reduction mode (optimizes execution for Helgrind analysis).
  • -b: Integrity Check. Enables periodic global balance verification to prove conservation of money.
  • -yN: Yield Injection. Forces threads to voluntarily yield the CPU N% of the time, artificially increasing context switching to stress-test lock boundaries.

Project Structure

├── src/
│   ├── bank.c          # Core banking logic and transaction handling
│   ├── teller.c        # Worker thread implementation
│   └── report.c        # Thread-safe reporting and barriers
├── include/
│   └── ledger.h        # Data structures and lock definitions
├── Makefile
└── README.md

Author: Luka Aladashvili

About

A thread-safe concurrent banking system implemented in C using POSIX threads. Features fine-grained locking, deadlock prevention via resource ordering, and custom barrier synchronization for consistent global reporting.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors