TTAS自旋锁lock方法中relaxed内存序加载的有效性与延迟问题
TTAS自旋锁中relaxed内存序加载的可见性问题
先看TTAS自旋锁的lock方法实现:
struct ttas_lock { ... void lock() { for (;;) { if (!lock_.exchange(true, std::memory_order_acquire)) { break; } while (lock_.load(std::memory_order_relaxed)); // <--- 自旋阶段 } } ... };
核心疑问解答
不会出现永远无法加载到false的情况,也不会因为relaxed内存序导致异常高的延迟,具体原因如下:
硬件缓存一致性的兜底保证
现代CPU的缓存一致性协议(如MESI)会强制维护共享数据的全局可见性。当持有锁的线程执行unlock操作(通常是lock_.store(false, std::memory_order_release))时,这个修改会被硬件同步到所有核心的缓存中——relaxed内存序只是不提供C++层面的happens-before同步关系,但不会屏蔽硬件层面的缓存同步机制。因此自旋的relaxed加载最终一定会读到锁释放后的false值。relaxed内存序的设计意图就是降低开销
TTAS锁的自旋阶段使用relaxed加载,正是为了减少缓存一致性流量:如果自旋阶段用acquire加载,每次读取都会触发严格的内存屏障,可能导致频繁的缓存无效化请求;而relaxed加载更轻量,只会在本地缓存中轮询,直到缓存行被硬件同步为最新值。这种设计反而能降低自旋阶段的开销,不会带来额外的高延迟。同步关系的边界清晰
真正需要release-acquire同步的是临界区内的数据,而非锁变量本身。当线程通过exchange(acquire语义)获取锁后,能保证看到之前持有锁线程在临界区内的所有修改;而锁变量lock_的可见性由硬件兜底,不需要依赖relaxed和release的同步关系。
内容的提问来源于stack exchange,提问作者for_stack
相关产品推荐
相关产品推荐

