--- id: cs-lock-free-patterns title: Lock-Free Patterns — atomic / CAS / queue category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [cs, concurrency, vibe-coding] tech_stack: { language: "C++ / Rust", applicable_to: ["CS", "Backend"] } applied_in: [] aliases: [lock-free, wait-free, CAS, compare and swap, atomic, MPSC, MPMC, ABA problem] --- # Lock-Free Patterns > Lock = 느린, deadlock 위험. **Atomic + CAS = lock-free**. Wait-free 가 강함. ## 📖 핵심 개념 - Atomic: 원자 operation. - CAS: Compare-And-Swap. - Lock-free: 1+ thread 가 progress. - Wait-free: 매 thread 가 progress. ## 💻 코드 패턴 ### Atomic counter ```rust use std::sync::atomic::{AtomicU64, Ordering}; let counter = AtomicU64::new(0); // Thread-safe counter.fetch_add(1, Ordering::SeqCst); let val = counter.load(Ordering::SeqCst); ``` ### CAS (Compare-And-Swap) ```rust let atomic = AtomicU64::new(0); loop { let old = atomic.load(Ordering::SeqCst); let new = old + 1; if atomic.compare_exchange(old, new, Ordering::SeqCst, Ordering::SeqCst).is_ok() { break; } // 다른 thread 가 변경. Retry. } ``` → "if 같으면 set". Atomic. ### Memory order ``` Relaxed: 매 thread 의 자체 ordering 만. Acquire / Release: 인접 op 의 ordering. SeqCst: total ordering (제일 안전, 느린). ``` ### TS / JavaScript SharedArrayBuffer ```ts const sab = new SharedArrayBuffer(8); const view = new Int32Array(sab); // Atomic Atomics.add(view, 0, 1); Atomics.compareExchange(view, 0, oldVal, newVal); Atomics.wait(view, 0, 0); Atomics.notify(view, 0); ``` → Worker 간 shared. ### Lock-free queue (Michael-Scott) ```rust struct Node { value: T, next: AtomicPtr>, } struct Queue { head: AtomicPtr>, tail: AtomicPtr>, } impl Queue { fn enqueue(&self, value: T) { let new_node = Box::into_raw(Box::new(Node { value, next: AtomicPtr::new(null_mut()) })); loop { let tail = self.tail.load(SeqCst); let next = unsafe { (*tail).next.load(SeqCst) }; if next.is_null() { if unsafe { (*tail).next.compare_exchange(null_mut(), new_node, SeqCst, SeqCst) }.is_ok() { self.tail.compare_exchange(tail, new_node, SeqCst, SeqCst).ok(); return; } } else { self.tail.compare_exchange(tail, next, SeqCst, SeqCst).ok(); } } } } ``` → Multi-producer multi-consumer. ### MPSC (single consumer) ```rust // Crossbeam (Rust) use crossbeam::channel::unbounded; let (tx, rx) = unbounded(); // Multiple producer thread::spawn(move || tx.send(1).unwrap()); // Single consumer let v = rx.recv().unwrap(); ``` → Lock-free queue. ### Crossbeam (Rust) ``` - Unbounded / bounded channel. - ArrayQueue / SegQueue. - AtomicCell. - Epoch-based GC. ``` ### ABA problem ``` Thread A: - Load X = 1. Thread B: - Set X = 2. - Set X = 1. Thread A: - CAS X (expect 1) = success. - → wrong (X 가 변경 됐는데 안 알아). ``` ```rust // Solution: tagged pointer (counter + value). let old: (u64, T) = atomic.load(); // counter + value let new = (old.0 + 1, new_value); atomic.compare_exchange(old, new, ...); ``` → Counter 가 increment. 같은 value 가 다른 counter. ### Memory reclamation ``` Lock-free 의 함정: - Free 한 node 의 다른 thread 가 still 참조. Solution: - Hazard pointer. - Epoch-based GC (crossbeam). - RCU (Read-Copy-Update). ``` ### Lock-free hash map ``` DashMap (Rust): - Sharded (16 partition). - 매 partition 의 Lock-free or fine lock. - 큰 throughput. ``` ```rust use dashmap::DashMap; let map: DashMap = DashMap::new(); map.insert("key".into(), 42); let v = map.get("key"); ``` ### Atomic reference counting (Rust Arc) ```rust use std::sync::Arc; use std::sync::atomic::AtomicUsize; let arc = Arc::new(MyData); let arc2 = arc.clone(); // count++ // Drop = count--. 0 = free. ``` ### Java AtomicInteger / AtomicReference ```java AtomicInteger counter = new AtomicInteger(0); counter.incrementAndGet(); AtomicReference head = new AtomicReference<>(); head.compareAndSet(expected, newValue); ``` ### Go (sync/atomic) ```go import "sync/atomic" var counter int64 atomic.AddInt64(&counter, 1) old := atomic.LoadInt64(&counter) atomic.CompareAndSwapInt64(&counter, old, old + 1) ``` ### Wait-free ``` Lock-free: 1+ thread 가 progress. Wait-free: 매 thread 가 progress. Wait-free = stronger. 보통 lock-free 가 충분. ``` ### Software Transactional Memory (STM) ```haskell -- Haskell atomically $ do x <- readTVar var writeTVar var (x + 1) ``` ```clojure ;; Clojure (dosync (alter counter inc)) ``` → Optimistic concurrency. Conflict 시 retry. ### Use case ``` - Counter (statistics). - Single producer queue (logging). - Lock-free hash (cache). - Reference count (shared ownership). - LSM tree memtable. - WAL (write-ahead log). ``` ### vs Mutex ``` Mutex: - Simple. - Block 가능 (sleep). - Deadlock 위험. Lock-free: - Complex. - Non-blocking. - 더 빠름 (high contention). - 더 어려움. → 작은 critical section = mutex. 큰 contention = lock-free. ``` ### Lock contention 측정 ``` perf record / perf report. - Hot mutex 발견. - Lock-free 의 candidate. → Profile 가 답. ``` ### Lock-free의 함정 ``` - ABA problem: tagged pointer. - Memory reclamation: hazard pointer / epoch. - Memory ordering: SeqCst 가 안전 default. - Algorithm 가 매우 어려움. - Test 어려움 (race rare). → Library (Crossbeam / Folly) 사용. 자체 X. ``` ### Folly (Facebook C++) ```cpp #include folly::MPMCQueue queue(1024); queue.write(42); int x; queue.read(x); ``` ### LMAX Disruptor (Java) ```java RingBuffer ringBuffer = ...; long sequence = ringBuffer.next(); Event event = ringBuffer.get(sequence); event.setValue(42); ringBuffer.publish(sequence); ``` → 매우 빠른 (millions / sec). ### Database 의 lock-free ``` MVCC: lock-free read. LSM tree: lock-free memtable insert. B-tree (some): lock-free split. → Modern DB 의 핵심. ``` ### When use? ``` ✓ High contention. ✓ Real-time (no block). ✓ Embedded / kernel. ✗ Low contention (mutex 충분). ✗ Logic 가 복잡. ✗ Team 가 expert X. → Profile 후. Library 사용. ``` ### Real-world - **Crossbeam** (Rust). - **Folly** (C++ Facebook). - **DashMap** (Rust hash). - **LMAX Disruptor** (Java). - **Java concurrent.atomic**. ## 🤔 의사결정 기준 | 작업 | 추천 | |---|---| | Counter | Atomic | | Queue | Lock-free queue (Crossbeam) | | Hash map | DashMap / ConcurrentHashMap | | Ref count | Arc / shared_ptr | | 큰 throughput | LMAX Disruptor | | Database | MVCC + LSM | | Complex sync | STM (Haskell / Clojure) | ## ❌ 안티패턴 - **자체 lock-free queue**: bug. - **No memory order**: race. - **No ABA fix**: corruption. - **No memory reclamation**: leak / use-after-free. - **Mutex on hot path**: contention. ## 🤖 LLM 활용 힌트 - Library 사용 (자체 X). - ABA + memory reclamation 가 큰 함정. - Profile + measure. - MVCC + LSM 가 DB 의 lock-free. ## 🔗 관련 문서 - [[CS_LockFree_Atomic]] - [[CS_MVCC_Concurrency]] - [[CS_Skip_List_Persistent_Data]]