atomic_cmp_exchange
Atomically compares and conditionally exchanges a value.
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 PlaygroundLive Demo Pending
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
atomic_cmp_exchange(dest, compare, value)
Parameters
| Parameter | Description |
|---|---|
dest | Integer lvalue to modify atomically |
compare | Expected current value |
value | New value to store if compare matches |
Return Value
Returns the original value at dest. If it equals compare, the exchange occurred.
Example
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
// Lock-free stack push
int oldTop;
do {
oldTop = stackTop;
nodeData[newNode].next = oldTop;
} while (atomic_cmp_exchange(stackTop, oldTop, newNode) != oldTop);Try-Lock
// 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
// Only update if value is still expected
int oldValue = atomic_cmp_exchange(data, expectedValue, newValue);
bool success = (oldValue == expectedValue);Lazy Initialization
// 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
// 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:
atomicCompSwap(dest, compare, value)
When compiled to HLSL:
InterlockedCompareExchange(dest, compare, value, originalValue)
When compiled to SPIR-V:
Uses OpAtomicCompareExchange instruction.
See Also
- atomic_exchange - Unconditional exchange
- atomic_add - Atomic add