Intrinsics2 min read

atomic_cmp_exchange

Atomically compares and conditionally exchanges a value.

Reading Time
2 min
Word Count
189
Sections
12
Try It Live

Test atomic_cmp_exchange in a live shader

Open the playground, start from a visual preset, and wire atomic_cmp_exchange into the fragment stage to see how it behaves with real values.

Open Playground

Live Demo Pending

This intrinsic does not yet have a self-contained interactive preview. Compute-only and external-resource intrinsics need a different demo path than the current fragment and 3D showcases.

The atomic_cmp_exchange function atomically compares the value at a memory location with an expected value, and if they match, stores a new value. Returns the original value.

Signature

bwsl
atomic_cmp_exchange(dest, compare, value)

Parameters

ParameterDescription
destInteger lvalue to modify atomically
compareExpected current value
valueNew value to store if compare matches

Return Value

Returns the original value at dest. If it equals compare, the exchange occurred.

Example

bwsl
pipeline LockFreeList {
pass "Main" {
compute "Main" [64, 1, 1] {
// Lock-free list insertion
int newNode = allocateNode();
int oldHead;
do {
// Read current head
oldHead = listHead[0];
// Point new node to current head
nodeNext[newNode] = oldHead;
// Try to update head to new node
} while (atomic_cmp_exchange(listHead[0], oldHead, newNode) != oldHead);
// Loop until CAS succeeds
}
}
}

Common Use Cases

Lock-Free Data Structures

bwsl
// Lock-free stack push
int oldTop;
do {
oldTop = stackTop;
nodeData[newNode].next = oldTop;
} while (atomic_cmp_exchange(stackTop, oldTop, newNode) != oldTop);

Try-Lock

bwsl
// Non-blocking lock attempt
int result = atomic_cmp_exchange(lock, 0, 1);
if (result == 0) {
// Successfully acquired lock
// ... critical section ...
atomic_exchange(lock, 0); // Release
} else {
// Lock was held, do something else
}

Conditional Update

bwsl
// Only update if value is still expected
int oldValue = atomic_cmp_exchange(data, expectedValue, newValue);
bool success = (oldValue == expectedValue);

Lazy Initialization

bwsl
// Initialize only once
int wasInitialized = atomic_cmp_exchange(initFlag, 0, 1);
if (wasInitialized == 0) {
// This thread should initialize
initializeData();
atomic_exchange(initComplete, 1);
}

Reference Counting

bwsl
// Decrement and check for zero
int oldCount, newCount;
do {
oldCount = refCount;
newCount = oldCount - 1;
} while (atomic_cmp_exchange(refCount, oldCount, newCount) != oldCount);
if (newCount == 0) {
cleanup();
}

CAS Pattern

Compare-And-Swap (CAS) is the foundation of most lock-free algorithms. The pattern is: read value, compute new value, try to exchange, retry if someone else modified it first.

ABA Problem

CAS can suffer from the ABA problem where a value changes from A to B back to A. Consider using versioned values or other techniques for complex data structures.

Compiled Output

When compiled to GLSL:

glsl
atomicCompSwap(dest, compare, value)

When compiled to HLSL:

hlsl
InterlockedCompareExchange(dest, compare, value, originalValue)

When compiled to SPIR-V:

Uses OpAtomicCompareExchange instruction.

See Also