In this lesson, you will learn how to safely share data between multiple worker threads using SharedArrayBuffer and Atomics to prevent data corruption.
The Problem: Race Conditions
When you run code in separate Worker Threads, each thread typically has its own isolated memory space. If you want two threads to work on the exact same piece of data, Node.js provides a SharedArrayBuffer. However, a dangerous problem arises: Race Conditions. If Thread A is reading a value while Thread B is writing to it, Thread A might read a "half-finished" or corrupted value.
Coordinating with Atomics
To coordinate access to this shared memory, we use the Atomics object. Think of Atomics as a traffic controller for your memory. It ensures that operations—like adding numbers or checking values—happen "atomically," meaning they are completed in a single, uninterruptible step.
Consider a scenario where two threads are trying to update a shared counter in a buffer:
// Inside a worker thread
const sharedBuffer = new Int32Array(workerData.sharedBuffer);
// Instead of sharedBuffer[0]++, which is risky:
// We use Atomics to ensure the update happens safely
Atomics.add(sharedBuffer, 0, 1);
// We can also wait for a specific condition
// This pauses the thread until another thread changes the value
Atomics.wait(sharedBuffer, 0, 0);
Why this matters
By using Atomics.add or Atomics.compareExchange, you force the CPU to treat the memory operation as a single unit of work. If Thread A starts an atomic operation, Thread B must wait for it to finish before it can touch that specific memory slot. This prevents the "lost update" problem where two threads read the same value, increment it, and write it back, effectively overwriting each other's progress.
This synchronization is the bridge between the high-performance raw speed of shared memory and the safety required for asynchronous multi-threaded programming. It allows your workers to talk to each other without needing to pass heavy messages back and forth through the event loop, keeping your system responsive and consistent.
Key Takeaway: Use SharedArrayBuffer to share memory between threads and rely on Atomics to ensure that updates are performed as single, uninterruptible steps, preventing race conditions.