In this lesson, you will learn how to prevent data corruption when multiple worker threads modify the same piece of memory simultaneously using atomic operations.
The Challenge: Memory Race Conditions
When you pass data between threads using postMessage, Node.js actually copies the data, which is safe but slow for large datasets. To avoid copying, we use a SharedArrayBuffer. This allows multiple threads to point to the exact same bytes in memory.
However, this creates a dangerous scenario: a race condition. Imagine two threads trying to increment a shared counter at the same time. Both might read the value 10 simultaneously, increment it to 11, and write it back. You’ve performed two operations, but your counter only reflects one.
Introducing Atomic Operations
To solve this, we use the Atomics object. An atomic operation is an "all-or-nothing" action that cannot be interrupted by another thread. When you perform an operation atomically, the CPU ensures that no other thread can touch that specific memory location until the current operation is finished.
Think of it like a single bathroom key in a busy house: only the person holding the key can enter, ensuring nobody else tries to use the facility at the exact same moment.
Putting it into code
If you want to increment a value inside a SharedArrayBuffer safely, you don't just use +=. You use Atomics.add:
// Assuming 'sharedBuffer' is a SharedArrayBuffer shared by threads
const int32 = new Int32Array(sharedBuffer);
// Instead of: int32[0]++ (Unsafe!)
// Use this:
Atomics.add(int32, 0, 1);
By calling Atomics.add(int32, 0, 1), you guarantee that the addition happens as a single, indivisible step. The hardware locks the memory address, performs the math, and releases the lock, effectively preventing other threads from seeing or writing a "partial" or "stale" state.
These operations are the foundation of high-performance parallel programming in Node.js, allowing your worker threads to coordinate complex tasks without relying solely on message passing.
Key Takeaway: Atomic operations provide a thread-safe way to manipulate shared memory, preventing race conditions by ensuring that memory updates are indivisible and protected from concurrent interference.