custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing…
C++ and Rust memory model skill for concurrent programming. Use when understanding memory ordering, writing lock-free data structures, using std::atomic or Rust atomics, diagnosing data races, or selecting the correct memory order for atomic operations. Activates on queries
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill memory-model --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/memory-modelContext preview
The summary Claude sees to decide when to auto-load this skill.
C++ and Rust memory model skill for concurrent programming. Use when understanding memory ordering, writing lock-free data structures, using std::atomic or Rust atomics, diagnosing data races, or selecting the correct memory order for atomic operations. Activates on queries
name: memory-model description: C++ and Rust memory model skill for concurrent programming. Use when understanding memory ordering, writing lock-free data structures, using std::atomic or Rust atomics, diagnosing data races, or selecting the correct memory order for atomic operations. Activates on queries about memory ordering, acquire-release, seq_cst, relaxed atomics, happens-before, memory barriers, std::atomic, or Rust atomic ordering.
Guide agents through C++ and Rust memory models: memory orderings, the happens-before relation, atomic operations, fences, and practical patterns for lock-free data structures.
Modern CPUs and compilers reorder operations for performance. The memory model specifies what reorderings are allowed and how synchronisation is achieved.
Ordering strength (weakest to strongest): Relaxed < Release/Acquire < AcqRel < SeqCst Stronger ordering = more synchronization = more correct, but slower Weaker ordering = fewer barriers = faster, but needs careful analysis
| Order | C++ | Rust | What it means | |-------|-----|------|--------------| | Relaxed | `memory_order_relaxed` | `Ordering::Relaxed` | No ordering guarantee; just atomicity | | Consume | `memory_order_consume` | (use Acquire) | Data dependency ordering | | Acquire | `memory_order_acquire` | `Ordering::Acquire` | This load sees all writes before the matching release | | Release | `memory_order_release` | `Ordering::Release` | All writes before this store are visible to acquire | | AcqRel | `memory_order_acq_rel` | `Ordering::AcqRel` | Both acquire and release on RMW ops | | SeqCst | `memory_order_seq_cst` | `Ordering::SeqCst` | Total order across all seq_cst operations |
#include <atomic>
#include <thread>
std::atomic<int> counter{0};
std::atomic<bool> ready{false};
// Producer thread
void producer() {
data = 42; // (1) write data
ready.store(true, std::memory_order_release); // (2) signal
}
// Consumer thread
void consumer() {
while (!ready.load(std::memory_order_acquire)); // (3) wait
assert(data == 42); // (4) guaranteed to see (1)
}Acquire-release guarantees: if thread A does a **release store** to X, and thread B does an **acquire load** that sees A's value, then all writes by A before the release are visible to B after the acquire.
Use case? ├── Counter (just needs atomicity, order irrelevant) → Relaxed ├── Reference counting (decrement + final check) → AcqRel (dec), Acquire (load 0 check) ├── Publish data from one thread to another → Release (store), Acquire (load) ├── Mutual exclusion / mutex implementation → AcqRel / SeqCst ├── Lock-free queue multiple producers/consumers → SeqCst (safest to start) └── Sequence number check (simple flag) → Release + Acquire
// Pattern 1: Spinlock
class Spinlock {
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock() {
while (flag.test_and_set(std::memory_order_acquire))
; // spin
}
void unlock() {
flag.clear(std::memory_order_release);
}
};
// Pattern 2: Reference counting
class RefCounted {
std::atomic<int> refcount{1};
public:
void addref() {
refcount.fetch_add(1, std::memory_order_relaxed); // only need atomicity
}
void release() {
if (refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
// AcqRel ensures we see all writes from other releasers
delete this;
}
}
};
// Pattern 3: One-time initialisation
class LazyInit {
std::atomic<void*> ptr{nullptr};
std::mutex mtx;
public:
void* get() {
void* p = ptr.load(std::memory_order_acquire);
if (p == nullptr) {
std::lock_guard lock(mtx);
p = ptr.load(std::memory_order_relaxed);
if (p == nullptr) {
p = create();
ptr.store(p, std::memory_order_release);
}
}
return p;
}
};use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
// Simple counter
let counter = Arc::new(AtomicUsize::new(0));
// Increment
counter.fetch_add(1, Ordering::Relaxed);
// Read
let val = counter.load(Ordering::Relaxed);
// Publish/subscribe pattern
static READY: AtomicBool = AtomicBool::new(false);
// Publisher thread
unsafe { DATA = 42; } // Write data
READY.store(true, Ordering::Release); // Signal
// Subscriber thread
while !READY.load(Ordering::Acquire) {}
let d = unsafe { DATA }; // Safe: guaranteed to see publisher's writeFences provide ordering without an atomic operation on a specific variable:
// C++ fence — equivalent to a global memory barrier std::atomic_thread_fence(std::memory_order_acquire); // Acquire fence std::atomic_thread_fence(std::memory_order_release); // Release fence // Typical use: multiple atomic writes then one fence relaxed_atomic_a.store(1, std::memory_order_relaxed); relaxed_atomic_b.store(2, std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_release); // barrier for all above sentinel.store(true, std::memory_order_relaxed);
| Mistake | Fix | |---------|-----| | Using Relaxed for publish/subscribe | Use Release on store, Acquire on load | | Using SeqCst everywhere | Profile first; use weakest correct ordering | | Forgetting that non-atomic loads are not atom
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Custom allocator skill for memory allocation strategies. Use when implementing…
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology,…
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring…
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers,…
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing,…
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC,…