3

The ECMAScript Language Specification states:

Atomics are carved in stone: Program transformations must not cause any Shared Data Block events whose [[Order]] is seq-cst to be removed from the is-agent-order-before Relation, nor to be reordered with respect to each other, nor to be reordered inside an agent-order slice with respect to events whose [[Order]] is unordered.

Does this (or another part of the specification) mean that the use of an atomic operation like Atomics.load or Atomics.store guarantees that all prior operations on SharedArrayBuffer objects will be completed first, even those on buffer objects other than one passed as an argument?

For example, in the code snippets below, does the reader agent observing the atomic update to i32View guarantee that the non-atomic update to f32View has also been completed, despite them being views of different SharedArrayBuffer objects?

const i32Buffer = new SharedArrayBuffer(4);
const f32Buffer = new SharedArrayBuffer(4);
// Writer agent

const i32View = new Int32Array(i32Buffer);
const f32View = new Float32Array(f32Buffer);

function setValue(value) {
  f32View[0] = value;
  Atomics.store(i32View, 0, 1);
}
// Reader agent

const i32View = new Int32Array(i32Buffer);
const f32View = new Float32Array(f32Buffer);

function getValue() {
  while (Atomics.load(i32View, 0) === 0) Atomics.pause();
  return f32View[0];
}
0

1 Answer 1

-1

The issue is just that the two writes happen on two different SharedArrayBuffer objects
Atomic ops only order memory inside the same shared block: nothing forces a write to SAB-B to become visible when you observe an atomic flag in SAB-A.
The reader can see the flag and still miss the float write, and that’s allowed by the spec.

the usual fix is to put the flag and the payload in a single buffer :

const buf = new SharedArrayBuffer(8);

// int32 flag    float32 value
const flag = new Int32Array(buf, 0, 1);
const value = new Float32Array(buf, 4, 1);

function setValue(v) {
  value[0] = v;
  Atomics.store(flag, 0, 1); // seq-cst / same SAB ==> ordered
}

function getValue() {
  while (Atomics.load(flag, 0) === 0) Atomics.pause();
  return value[0];
}

atomic ordering doesn’t cross SAB boundaries. if you need ordering, keep both fields in the same buffer.

Sign up to request clarification or add additional context in comments.

3 Comments

"and that’s allowed by the spec" - can you point to the specific part of the spec that details the ordering requirements of operations on separate buffers?
To be fair with this answer, I think the specs uses a form akin to "if the events have overlapping data blocks" in most cases, rather than "if the events have disjoint data blocks", which makes it a lot more harder to quote the specs correctly since all entry points have to be referenced in order to be sure they all accept only the cases where the data blocks aren't disjoined.
"atomic ordering doesn’t cross SAB boundaries. if you need ordering, keep both fields in the same buffer" I have seen this limitation implied across various code samples and tutorials (such as this one), but have so far been unable to find an authoritative source which confirms that it exists, either within the language specification or popular engine implementations such as V8/SpiderMonkey.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.