Atomics.wait and Atomics.notify in Web Workers
Atomics.wait and Atomics.notify provide a
low-level synchronization mechanism for managing concurrent JavaScript
execution across Web Workers. When workers share memory via a
SharedArrayBuffer, these methods allow threads to pause
execution and wait for specific state changes without consuming CPU
resources through busy-waiting, and then signal each other when data is
ready to be processed.
The Need for Synchronization
When multiple Web Workers operate on the same
SharedArrayBuffer, they risk data races if one worker reads
from a memory location while another writes to it. While basic
Atomics operations (such as Atomics.add or
Atomics.exchange) ensure individual read-modify-write
operations are indivisible, complex tasks require threads to pause and
wait for multi-step processes to complete.
Without synchronization primitives, workers would need to poll memory
inside a loop (while loop), which maxes out CPU cores and
reduces performance. Atomics.wait and
Atomics.notify eliminate polling by leveraging the
operating system’s native thread-blocking capabilities.
How Atomics.wait Works
Atomics.wait() blocks a worker thread until a specific
condition is met or an optional timeout expires.
- Signature:
Atomics.wait(typedArray, index, expectedValue, [timeout]) - Behavior:
- Checks if the value at
typedArray[index]equalsexpectedValue. - If the values match, the browser puts the calling thread to sleep.
- If the value does not match, the call returns immediately with
"not-equal", preventing sleep on outdated conditions. - Once awakened by
Atomics.notify()or a timeout, it returns"ok"or"timed-out".
- Checks if the value at
Constraint: To prevent user interface freezes,
Atomics.wait() is forbidden on the main thread and will
throw a TypeError if invoked there. It can only be called
inside dedicated Web Workers.
How Atomics.notify Works
Atomics.notify() wakes up one or more workers that are
currently suspended in an Atomics.wait() call on a
specified array index.
- Signature:
Atomics.notify(typedArray, index, [count]) - Behavior:
- Identifies threads sleeping on the specified index.
- Wakes up the number of threads specified by
count(default isInfinity, waking all waiting threads). - Returns the number of workers that were successfully awakened.
Unlike Atomics.wait(), Atomics.notify() can
be executed safely from both Web Workers and the main thread.
The Coordination Workflow
A standard producer-consumer pattern between workers follows this sequence:
- Setup: Both the producer worker and consumer worker
receive the same
SharedArrayBufferwrapped in anInt32Array. - Consumer Waits: The consumer checks a
synchronization index (e.g., index
0, initialized to0). It callsAtomics.wait(sharedArray, 0, 0). The consumer enters a sleep state. - Producer Works: The producer writes data to the
buffer, updates index
0to a new state (e.g.,1), and callsAtomics.notify(sharedArray, 0, 1). - Consumer Resumes: The consumer thread wakes up,
receives
"ok", reads the newly produced data, and resets the synchronization index.
Key Rules and Restrictions
- Typed Array Types:
Atomics.waitandAtomics.notifyoperate exclusively onInt32ArrayorBigInt64Arrayviews over aSharedArrayBuffer. - Cross-Origin Isolation: Using
SharedArrayBufferrequires the hosting server to deliver the proper HTTP headers (Cross-Origin-Opener-Policy: same-originandCross-Origin-Embedder-Policy: require-corp) for security reasons.