7.2 KiB
7.2 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| cs-lock-free-patterns | Lock-Free Patterns — atomic / CAS / queue | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
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
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)
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
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)
struct Node<T> {
value: T,
next: AtomicPtr<Node<T>>,
}
struct Queue<T> {
head: AtomicPtr<Node<T>>,
tail: AtomicPtr<Node<T>>,
}
impl<T> Queue<T> {
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)
// 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 가 변경 됐는데 안 알아).
// 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.
use dashmap::DashMap;
let map: DashMap<String, u32> = DashMap::new();
map.insert("key".into(), 42);
let v = map.get("key");
Atomic reference counting (Rust Arc)
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
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();
AtomicReference<Node> head = new AtomicReference<>();
head.compareAndSet(expected, newValue);
Go (sync/atomic)
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
atomically $ do
x <- readTVar var
writeTVar var (x + 1)
;; 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++)
#include <folly/MPMCQueue.h>
folly::MPMCQueue<int> queue(1024);
queue.write(42);
int x;
queue.read(x);
LMAX Disruptor (Java)
RingBuffer<Event> 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.