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

Atomics.or()

Methode

Führt atomar ein bitweises OR zwischen dem Wert an <code>typedArray[index]</code> und <code>value</code> aus, speichert das Ergebnis und gibt den alten Wert zurück.

seit JavaScript ES2017 Kategorie: method-property

Signatur

Atomics.or(typedArray, index, value)

Beschreibung

Atomics.or() liest den Wert an einer Position eines Integer-TypedArrays, verknüpft ihn bitweise per OR mit value und schreibt das Ergebnis zurück. Diese drei Schritte laufen als eine unteilbare Operation ab. Kein anderer Thread (Worker) kann dazwischen schreiben, auch wenn der Speicher über einen SharedArrayBuffer geteilt wird.

Typischerweise setzt man damit Flags oder Bitmasken in gemeinsam genutztem Speicher, etwa „Worker 3 ist fertig“ oder „Ressource belegt“. Mit dem normalen Ausdruck arr[i] |= mask würde man dagegen eine Race Condition riskieren: Zwei Worker lesen gleichzeitig denselben alten Wert, und eines der gesetzten Bits geht verloren.

Der Rückgabewert ist der Wert vor der Operation. Daran sieht man, ob ein Bit schon gesetzt war. So lässt sich zum Beispiel ein einfaches „Test-and-Set“ bauen.

Die Methode funktioniert auch mit einem gewöhnlichen ArrayBuffer. Atomar im Sinne mehrerer Threads ist sie aber nur mit einem SharedArrayBuffer.

Parameter

Name Typ Default Beschreibung
$typedArray Pflicht Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|BigInt64Array|BigUint64Array Ganzzahliges TypedArray, meist auf einem SharedArrayBuffer. Float32Array, Float64Array und Uint8ClampedArray sind nicht erlaubt.
$index Pflicht number Position im typedArray, an der die OR-Verknüpfung stattfindet.
$value Pflicht number|bigint Zahl, mit der bitweise OR verknüpft wird. Bei BigInt64Array und BigUint64Array muss sie ein bigint sein.

Rückgabewert

Typ
number|bigint
Beschreibung
Der alte Wert an typedArray[index] vor der Operation.

Beispiele

Grundlegende Verwendung

const sab = new SharedArrayBuffer(4);
const ta = new Uint8Array(sab);
ta[0] = 0b0101; // 5

const alt = Atomics.or(ta, 0, 0b0011); // 3
console.log(alt);          // alter Wert
console.log(Atomics.load(ta, 0)); // 5 | 3 = 7
5 7

Status-Flags mehrerer Worker setzen

// main.js
const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
const status = new Int32Array(sab);
const workerAnzahl = 4;

for (let id = 0; id < workerAnzahl; id++) {
  const w = new Worker('worker.js');
  w.postMessage({ sab, id });
}

// worker.js
self.onmessage = ({ data: { sab, id } }) => {
  const status = new Int32Array(sab);
  // ... Arbeit erledigen ...
  Atomics.or(status, 0, 1 << id); // eigenes Bit atomar setzen
  Atomics.notify(status, 0);
};

Test-and-Set: prüfen, ob ein Bit schon gesetzt war

const flags = new Int32Array(new SharedArrayBuffer(4));
const BELEGT = 0b1;

const tryAcquire = () => (Atomics.or(flags, 0, BELEGT) & BELEGT) === 0;

console.log(tryAcquire()); // erster Aufruf bekommt die Ressource
console.log(tryAcquire()); // schon belegt
Atomics.and(flags, 0, ~BELEGT); // freigeben
console.log(tryAcquire());
true false true

Mit BigInt64Array für 64-Bit-Masken

const big = new BigInt64Array(new SharedArrayBuffer(8));
Atomics.or(big, 0, 1n << 40n);
console.log(Atomics.load(big, 0));
1099511627776n

// Wichtig · Fallstricke

  • TypeError, wenn das Array kein erlaubtes Integer-TypedArray ist oder bei BigInt-Arrays kein bigint übergeben wird. Zahlen und BigInts lassen sich nicht mischen.
  • RangeError, wenn index außerhalb des Arrays liegt.
  • value wird auf den Elementtyp gekürzt. Bei Uint8Array zählen z. B. nur die unteren 8 Bits.
  • SharedArrayBuffer steht im Browser nur in einem cross-origin isolated Kontext zur Verfügung. Dafür braucht es die Header Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp. Prüfen lässt sich das mit self.crossOriginIsolated.
  • Innerhalb eines einzelnen Threads bringt Atomics.or() gegenüber |= keinen Vorteil, nur etwas Mehraufwand.
  • Die Methode wird in allen modernen Browsern und ab Node.js 8.10 unterstützt.