原子标志自旋等待
Atomic Flag Spinwait
题目详情
在超低延迟交易系统中,线程同步通常使用自旋等待而非操作系统级互斥锁,以消除上下文切换开销。std::atomic_flag 是 C++ 中最简单的原子类型,保证无锁,是构建低延迟同步原语的理想基础。
任务:实现可复用的自旋等待屏障 SpinWaitBarrier。多个线程在 barrier 上等待,当所有线程到达后同时释放继续执行。使用 atomic_flag 和自旋循环实现,不使用 mutex 或 condition_variable。
英文原题
In ultra-low-latency trading systems, thread synchronization is often implemented using spin-locks or spin-wait loops rather than OS-level mutexes to eliminate context-switch overhead. The std::atomic_flag is the simplest atomic type in C++ and is guaranteed to be lock-free, making it an excellent building block for low-latency synchronization primitives.
Task
Implement a reusable spin-wait barrier for exactly two threads by completing the SpinBarrier class and its wait() method. The wait() met
解析
问题分析
std::atomic_flag 是 C++ 唯一的无锁原子类型,适用于自旋锁等场景。相比 std::atomic<bool>,它保证在所有平台上都是无锁的。自旋等待适合临界区极短(< 100 周期)的场景。
实现
class SpinLock {
std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
public:
void lock() { while (flag_.test_and_set(std::memory_order_acquire))
__builtin_ia32_pause(); } // x86 PAUSE 指令减少功耗
bool try_lock() { return !flag_.test_and_set(std::memory_order_acquire); }
void unlock() { flag_.clear(std::memory_order_release); }
};复杂度与边界
- 时间复杂度:lock 取决于竞争,try_lock O(1)
- 空间复杂度:O(1)
- 边界条件:(1) 持有自旋锁时不可睡眠 (2) 不可递归 (3) 仅适合纳秒级临界区
英文解析
Analysis
`std::atomic_flag` is C++'s only lock-free atomic type, suitable for spinlock implementations. Unlike `std::atomic
Solution
class SpinLock {
std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
public:
void lock() { while (flag_.test_and_set(std::memory_order_acquire))
__builtin_ia32_pause(); } // x86 PAUSE instruction reduces power consumption
bool try_lock() { return !flag_.test_and_set(std::memory_order_acquire); }
void unlock() { flag_.clear(std::memory_order_release); }
};Complexity & Edge Cases
- Time complexity: lock depends on contention; try_lock O(1)
- Space complexity: O(1)
- Edge cases: (1) Must not sleep while holding spinlock (2) Not recursive — same thread re-locking causes deadlock (3) Only suitable for nanosecond-scale critical sections
Key Considerations
- Critical section duration: Spinwait only suitable for critical sections <1μs; longer sections waste CPU cycles and cause cache line contention
- Exponential backoff: Pure spin burns CPU; add exponential backoff (yield, then pause, then sleep) to reduce contention on high-load systems
- NUMA awareness: Atomic flag contention across NUMA nodes has 2-5x higher latency than within-node; prefer per-core data structures for NUMA systems
- Fairness: Spinwait provides no fairness guarantee; luckier threads acquire lock more frequently — not suitable where fairness is a correctness requirement