Principle:ClickHouse ClickHouse Portable Atomic Operations
| Knowledge Sources | |
|---|---|
| Domains | Concurrency, Portability |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
Provide lock-free atomic operations that work correctly across different CPU architectures with varying native atomic support.
Description
This principle addresses the challenge of implementing efficient lock-free algorithms on diverse hardware platforms. Different CPU architectures provide different atomic primitives: some offer load-linked/store-conditional (LL/SC) instructions while others provide compare-and-swap (CAS). The implementation adapts to available hardware capabilities through architecture-specific definitions while presenting a uniform API. On architectures with LL/SC, operations are implemented directly using those primitives for efficiency. On CAS-only architectures, operations are built using CAS loops with appropriate retry logic.
Usage
Use this principle when building concurrent data structures or synchronization primitives that must work efficiently across multiple architectures without relying on compiler-specific atomic builtins or C11/C++11 atomics, particularly for systems-level code targeting older or embedded platforms.
Theoretical Basis
Lock-free programming requires atomic read-modify-write operations that either succeed completely or fail without partial updates being visible. The fundamental primitives are:
- Compare-and-Swap (CAS): Atomically compares memory location with expected value and swaps if equal, returning old value
- Load-Linked/Store-Conditional (LL/SC): Pair of instructions where LL loads a value and marks it, SC stores only if the location hasn't been modified
These primitives have different performance characteristics: LL/SC can be more efficient for some operations as it avoids the retry penalty of CAS when contention is low, but CAS is more widely available.
Memory barriers ensure proper ordering of operations across threads. A full memory barrier prevents reordering of loads and stores across the barrier, which is essential for publish-subscribe patterns and lock-free algorithms.
Derived operations like fetch-and-add can be implemented efficiently using either primitive. The key insight is that with proper retry loops, CAS can emulate LL/SC and vice versa, allowing a single API to support both models.