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

Atomics.store()

Methode

Schreibt einen Wert atomar an eine Position in einem Integer-TypedArray und gibt den geschriebenen Wert zurück, nicht den alten.

seit JavaScript ES2017 Kategorie: method-property

Signatur

Atomics.store(typedArray, index, value)

Beschreibung

Atomics.store() ist eine statische Methode des Namensraums Atomics. Sie schreibt einen Wert atomar an eine Stelle in einem Integer-TypedArray. Atomar bedeutet: Andere Threads, zum Beispiel Web Worker oder Node.js-worker_threads, die denselben SharedArrayBuffer nutzen, sehen nie einen halb geschriebenen Wert. Außerdem sorgt der Aufruf für eine feste Reihenfolge der Speicherzugriffe (sequentiell konsistent): Alles, was vor dem store geschrieben wurde, ist für einen Thread sichtbar, der den Wert danach mit Atomics.load() liest.

Man nutzt die Methode vor allem, um einem anderen Thread etwas mitzuteilen, etwa mit Status-Flags („Daten bereit“, „Abbruch angefordert“), Zählern oder Indizes in Ringpuffern. Ein normaler Schreibzugriff wie ta[i] = v kann vom Compiler oder der CPU umsortiert werden. Er ist deshalb für die Abstimmung zwischen Threads nicht zuverlässig.

Wichtig: Die Methode gibt den umgewandelten Eingabewert zurück. Das ist weder der alte Wert (anders als bei Atomics.exchange()) noch zwingend der Wert, der tatsächlich im Array steht. Läuft der Wert über den Wertebereich des Elementtyps hinaus, steht im Array ein anderer Wert als der, den die Methode zurückgibt.

Parameter

Name Typ Default Beschreibung
$typedArray Pflicht Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|BigInt64Array|BigUint64Array Ein Integer-TypedArray, meist über einem SharedArrayBuffer. Float32Array, Float64Array und Uint8ClampedArray sind nicht erlaubt.
$index Pflicht number Position im typedArray, an die geschrieben wird.
$value Pflicht number|bigint Der zu schreibende Wert. Bei BigInt64Array/BigUint64Array muss es ein bigint sein, sonst eine Zahl. Zahlen werden vorher in eine Ganzzahl umgewandelt (Nachkommastellen fallen weg).

Rückgabewert

Typ
number|bigint
Beschreibung
Der geschriebene Wert nach der Umwandlung in eine Ganzzahl (bzw. BigInt). Er wird nicht auf den Wertebereich des Elementtyps gekürzt und ist nicht der vorherige Wert.

Beispiele

Einfaches atomares Schreiben

const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4);
const ta = new Int32Array(sab);

const result = Atomics.store(ta, 0, 42);
console.log(result);             // Rückgabewert
console.log(Atomics.load(ta, 0)); // Wert im Array
42 42

Rückgabewert vs. tatsächlich gespeicherter Wert

const ta = new Int8Array(new SharedArrayBuffer(2));

// Nachkommastellen werden abgeschnitten
console.log(Atomics.store(ta, 0, 12.9)); // 12

// Überlauf: Rückgabe ist 300, im Int8Array landet 300 mod 256 = 44
console.log(Atomics.store(ta, 1, 300));  // 300
console.log(ta[1]);                      // 44
12 300 44

Status-Flag zwischen Hauptthread und Worker (Node.js)

import { Worker } from 'node:worker_threads';

const sab = new SharedArrayBuffer(8);
const flags = new Int32Array(sab);

const worker = new Worker(`
  const { workerData } = require('node:worker_threads');
  const flags = new Int32Array(workerData);
  Atomics.wait(flags, 0, 0);      // schlafen, bis Index 0 nicht mehr 0 ist
  console.log('Worker: Signal erhalten, Wert =', Atomics.load(flags, 0));
`, { eval: true, workerData: sab });

setTimeout(() => {
  Atomics.store(flags, 0, 1);  // Flag atomar setzen …
  Atomics.notify(flags, 0, 1); // … und wartenden Worker wecken
}, 100);
Worker: Signal erhalten, Wert = 1

BigInt64Array verwenden

const big = new BigInt64Array(new SharedArrayBuffer(16));
console.log(Atomics.store(big, 0, 9007199254740993n));

try {
  Atomics.store(big, 1, 5); // number statt bigint
} catch (e) {
  console.log(e.constructor.name);
}
9007199254740993n TypeError

// Wichtig · Fallstricke

  • Rückgabewert-Falle: Die Methode gibt den umgewandelten Eingabewert zurück, nicht den alten Inhalt und nicht den gekürzten Wert im Array. Wer den alten Wert braucht, nimmt Atomics.exchange().
  • Fehler: Ein TypeError kommt bei einem ungültigen Array-Typ (Float-Arrays, Uint8ClampedArray, normale Arrays) oder beim Mischen von number und bigint. Ein RangeError kommt bei einem Index außerhalb des Arrays.
  • Kein Aufwecken: store weckt keine Threads, die in Atomics.wait() warten. Dafür muss man zusätzlich Atomics.notify() aufrufen.
  • Nicht geteilter Speicher: Die Methode funktioniert auch mit einem normalen ArrayBuffer. Einen Nutzen hat sie aber nur bei einem SharedArrayBuffer.
  • Browser-Kompatibilität: Atomics.store() gibt es in allen modernen Browsern und in Node.js 8.10+. SharedArrayBuffer ist im Browser aber nur in einem cross-origin isolated Kontext verfügbar. Dafür braucht die Seite die HTTP-Header Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp. Prüfen lässt sich das mit crossOriginIsolated.
  • Keine Lese-Ändern-Schreiben-Operation: Für atomares Hochzählen nimmt man Atomics.add(), nicht load plus store. Sonst kann es zu Race Conditions kommen.