Documentation for sub cas

Documentation for sub cas, assembled from the following types:

class atomicint

From atomicint

(atomicint) sub cas

Defined as:

multi sub cas(atomicint $target is rwint $expectedint $value)
multi sub cas(atomicint $target is rwInt() $expectedInt() $value)
multi sub cas(atomicint $target is rw&operation)

Performs an atomic compare and swap of the native integer value in location $target. The first two forms have semantics like:

my int $seen = $target;
if $seen == $expected {
    $target = $value;
}
return $seen;

Except it is performed as a single hardware-supported atomic instruction, as if all memory access to $target were blocked while it took place. Therefore it is safe to attempt the operation from multiple threads without any other synchronization. For example:

my atomicint $master = 0;
await start {
    if cas($master01== 0 {
        say "Master!"
    }
} xx 4

Will reliably only ever print Master! one time, as only one of the threads will be successful in changing the 0 into a 1.

Both $expected and $value will be coerced to Int and unboxed if needed. An exception will be thrown if the value cannot be represented as a 64-bit integer. If the size of atomicint is only 32 bits then the values will be silently truncated to this size.

The third form, taking a code object, will first do an atomic fetch of the current value and invoke the code object with it. It will then try to do an atomic compare and swap of the target, using the value passed to the code object as $expected and the result of the code object as $value. If this fails, it will read the latest value, and retry, until a CAS operation succeeds. Therefore, an atomic multiply of an atomicint $i by 2 could be implemented as:

cas $i-> int $current { $current * 2 }

If another thread changed the value while $current * 2 was being calculated then the block would be called again with the latest value for a further attempt, and this would be repeated until success.