Start · Sprachen · JavaScript · Referenz · Atomics.wait()

Atomics.wait()

Methode

Prüft, ob an einer Stelle im gemeinsamen Speicher ein bestimmter Wert steht, und blockiert dann den Thread, bis er per <code>Atomics.notify()</code> geweckt wird oder ein Timeout abläuft.

seit JavaScript ES2017 (Baseline: alle modernen Browser, Node.js 8 Kategorie: method-property

Signatur

Atomics.wait(typedArray, index, value, timeout)

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));
not-equal timed-out

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`);
Gewartet: ~250 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));
}
Worker geweckt: ok Wert: 1

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() einen TypeError aus (Hauptthread darf nicht blockieren). Stattdessen Atomics.waitAsync() (ES2024) verwenden oder in einem Worker arbeiten.
  • Nur Int32Array/BigInt64Array auf einem SharedArrayBuffer: Andere Arrays führen zu einem TypeError.
  • Cross-Origin-Isolation: Im Browser ist SharedArrayBuffer nur verfügbar, wenn die Seite die Header Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp sendet (prüfbar mit crossOriginIsolated). 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 jemand notify aufgerufen 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.