Shared Memory

Shared structs, SharedArrays and atomics, which many threads read and write in place.

Everything here comes from "@arv/threads".

Shared memory holds data that many threads read and write in place, with no copying. Reads and writes aren't ordered between threads. A Lock, a Channel, joining a thread, or an atomic operation is what orders them.

struct({ x: f64, n: i32, done: bool, name: str, next: ref<T>() }) A shared struct type. new S() makes a zeroed one, and Struct<typeof S> is the type of its values.
f64, i32, u8, bool, str, ref<T>() Field kinds: a number, a 32-bit integer, a byte, a boolean, a string (interned), and a reference to a struct, a SharedArray, a Channel, a Lock or a Condition (or null).
new SharedArray(Number | i32 | u8 | Boolean | String | S, length) A fixed-length array of numbers, i32s, bytes, booleans, strings or structs, stored inline.
atomic.add(s, "field", v), atomic.add(array, i, v) An atomic operation on an i32 field or on an element of a SharedArray<i32>: load, store, add, sub, and, or, xor, exchange, compareExchange, wait and notify. Compiled, it's that Atomics call itself.

Integers

i32 and u8 are types too. They're numbers, kept the way an Int32Array or a Uint8Array keeps them, so 2³¹ wraps and 256 is 0.

The checker requires that what you store into one is an integer. That means integer arithmetic, or an explicit conversion such as Math.round(x) or x | 0. A number that may have a fraction isn't allowed, because the store would truncate it silently.

Atomics and Locks

With an atomic counter, threads can claim work with no lock:

const Work = struct({next: i32});
function worker(work: Struct<typeof Work>, n: number) {
  for (let i; (i = atomic.add(work, 'next', 1)) < n;) process(i); // Claims each item once.
}

A lock turns several reads and writes into one step. A struct can hold its own lock, just as it can hold a channel, and using releases the lock at the end of the block:

const Account = struct({balance: f64, deposits: i32, lock: ref<Lock>()});

function deposit(account: Struct<typeof Account>, amount: number) {
  using _ = account.lock!.hold();
  account.balance += amount;
  account.deposits++;
}

Freeing, and Structs That Refer to Themselves

Structs and SharedArrays are reference counted, and they're freed when no thread can reach them. To declare a struct that refers to its own type, use an interface:

interface Node {
  value: number;
  next: Node | null;
}
const Node = struct<Node>({value: f64, next: ref<Node>()});

Reference Counting explains how they're counted and freed.

Docs