Signatur
Beschreibung
Atomics.wait() ist ein einfaches Mittel, um Threads zu synchronisieren. Die Methode liest atomar den Wert an Position index eines Int32Array oder BigInt64Array, das auf einem SharedArrayBuffer liegt. Stimmt dieser Wert mit value überein, legt sich der aufrufende Thread schlafen. Er wacht erst wieder auf, wenn ein anderer Thread Atomics.notify() für dieselbe Stelle aufruft oder das optionale timeout (in Millisekunden) abgelaufen ist.
Weil Prüfen und Einschlafen in einem einzigen, unteilbaren Schritt passieren, kann kein Weckruf „verloren gehen“ – genau das unterscheidet die Methode von einer selbstgebauten Warteschleife. Aus Atomics.wait() und Atomics.notify() lassen sich Mutexe, Semaphoren, Bedingungsvariablen oder Produzenten-Konsumenten-Warteschlangen zwischen Web Workern bzw. Node.js-worker_threads bauen.
Wichtig: Der Aufruf blockiert den Thread komplett. Deshalb ist er im Hauptthread von Browsern nicht erlaubt und löst dort einen TypeError aus. Im Hauptthread nimmt man stattdessen die nicht blockierende Variante Atomics.waitAsync(). In Node.js darf der Hauptthread dagegen Atomics.wait() aufrufen – das wird manchmal als synchrones sleep genutzt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $typedArray Pflicht | Int32Array|BigInt64Array | Ein Integer-Array, das auf einem SharedArrayBuffer liegt. Andere Typen oder ein normaler ArrayBuffer lösen einen TypeError aus. |
|
| $index Pflicht | number | Die Position im typedArray, an der gewartet wird. Liegt sie außerhalb des Arrays, gibt es einen RangeError. |
|
| $value Pflicht | number|bigint | Der erwartete Wert. Nur wenn an index genau dieser Wert steht, schläft der Thread ein. Bei BigInt64Array muss es ein bigint sein. |
|
| $timeout | number | Infinity | Die längste Wartezeit in Millisekunden. NaN wird als Infinity behandelt, negative Werte als 0. |
Beispiele
Grundlagen: Rückgabewerte in Node.js
// Node.js: Der Hauptthread darf blockieren
const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
const ia = new Int32Array(sab);
// Wert ist 0, erwartet wird 1 → kein Warten
console.log(Atomics.wait(ia, 0, 1));
// Wert ist 0, erwartet wird 0 → schläft 100 ms, niemand weckt
console.log(Atomics.wait(ia, 0, 0, 100));
Synchrones sleep() in Node.js
const sleep = (ms) => {
const ia = new Int32Array(new SharedArrayBuffer(4));
Atomics.wait(ia, 0, 0, ms);
};
const start = Date.now();
sleep(250);
console.log(`Gewartet: ~${Math.round((Date.now() - start) / 50) * 50} ms`);
Worker wartet auf ein Signal (Node.js worker_threads)
import { Worker, isMainThread, workerData } from 'node:worker_threads';
if (isMainThread) {
const sab = new SharedArrayBuffer(4);
const flag = new Int32Array(sab);
const worker = new Worker(new URL(import.meta.url), { workerData: sab });
setTimeout(() => {
Atomics.store(flag, 0, 1); // Daten sind bereit
Atomics.notify(flag, 0, 1); // einen Wartenden wecken
}, 500);
} else {
const flag = new Int32Array(workerData);
// Schlafen, solange flag[0] noch 0 ist
const result = Atomics.wait(flag, 0, 0);
console.log('Worker geweckt:', result, 'Wert:', Atomics.load(flag, 0));
}
Einfacher Mutex im Web Worker
// worker.js – ia ist ein Int32Array auf einem SharedArrayBuffer
const UNLOCKED = 0, LOCKED = 1;
const lock = (ia, i = 0) => {
while (Atomics.compareExchange(ia, i, UNLOCKED, LOCKED) !== UNLOCKED) {
Atomics.wait(ia, i, LOCKED); // schlafen, solange gesperrt
}
};
const unlock = (ia, i = 0) => {
Atomics.store(ia, i, UNLOCKED);
Atomics.notify(ia, i, 1);
};
self.onmessage = ({ data: sab }) => {
const ia = new Int32Array(sab);
lock(ia);
// ... kritischer Abschnitt ...
unlock(ia);
self.postMessage('fertig');
};
// Wichtig · Fallstricke
- Nicht im Browser-Hauptthread: Dort löst
Atomics.wait()einenTypeErroraus (Hauptthread darf nicht blockieren). StattdessenAtomics.waitAsync()(ES2024) verwenden oder in einem Worker arbeiten. - Nur
Int32Array/BigInt64Arrayauf einemSharedArrayBuffer: Andere Arrays führen zu einemTypeError. - Cross-Origin-Isolation: Im Browser ist
SharedArrayBuffernur verfügbar, wenn die Seite die HeaderCross-Origin-Opener-Policy: same-originundCross-Origin-Embedder-Policy: require-corpsendet (prüfbar mitcrossOriginIsolated). Das ist eine Schutzmaßnahme gegen Spectre. - Grundlose Weckrufe einplanen: Nach dem Aufwachen den Zustand immer erneut prüfen, am besten in einer Schleife (siehe Mutex-Beispiel).
"ok"heißt nur, dass jemandnotifyaufgerufen hat. - Performance: Wartende Threads verbrauchen keine CPU, anders als Warteschleifen mit Dauerabfrage. Wenn aber niemand weckt und kein Timeout gesetzt ist, hängt ein Worker für immer.
- Die Zeitauflösung des Timeouts kann aus Sicherheitsgründen ungenau sein.