为何我的MCS锁性能表现逊于简易自旋锁?
一篇技术文章指出:
自旋锁除了单纯自旋等待锁的问题外,还存在一个根本性缺陷:每次尝试获取锁都需要将包含该锁的缓存行迁移到本地CPU。对于竞争激烈的锁,这种缓存行抖动会严重影响性能。
...
通过将自旋锁扩展为每个CPU的独立结构,MCS锁能够消除简易自旋锁遇到的大部分缓存行抖动问题,尤其是在锁竞争激烈的场景下。
为验证这一效果,我编写了基准测试代码,完整代码可查看指定仓库版本。
简易自旋锁实现
代码基于一篇互斥锁、自旋锁性能测试的文章修改而来。该锁在基准测试结果中标记为spinlock (amd)。
pub struct RawSpinlock { locked: AtomicBool, } unsafe impl RawMutex for RawSpinlock { // ... fn lock(&self) { loop { let was_locked = self.locked.load(Ordering::Relaxed); if !was_locked && self .locked .compare_exchange_weak(was_locked, true, Ordering::Acquire, Ordering::Relaxed) .is_ok() { break; } spin_loop() } } unsafe fn unlock(&self) { self.locked.store(false, Ordering::Release); } }
MCS锁实现
代码基于NUMA自旋锁项目修改,该项目源自libc-alpha邮件列表的讨论。该锁在基准测试结果中标记为spinlock (mcs)。
struct Node { next: AtomicPtr<Self>, locked: AtomicBool, } #[thread_local] static mut NODE: Node = Node { next: AtomicPtr::new(null_mut()), locked: AtomicBool::new(false), }; pub struct RawSpinlock { tail: AtomicPtr<Node>, } unsafe impl RawMutex for RawSpinlock { // ... fn lock(&self) { unsafe { NODE.next = AtomicPtr::new(null_mut()); NODE.locked = AtomicBool::new(false); } let node = unsafe { &mut NODE as *mut _ }; let prev = self.tail.swap(node, Ordering::Acquire); if prev.is_null() { return; } unsafe { (*prev).next.store(node, Ordering::Relaxed) }; while unsafe { !NODE.locked.load(Ordering::Acquire) } { spin_loop(); } } unsafe fn unlock(&self) { let node = &mut NODE as *mut _; let mut next = NODE.next.load(Ordering::Relaxed); if next.is_null() { if self .tail .compare_exchange(node, null_mut(), Ordering::Release, Ordering::Relaxed) .is_ok() { return; } loop { next = NODE.next.load(Ordering::Relaxed); if !next.is_null() { break; } spin_loop(); } } unsafe { (*next).locked.store(true, Ordering::Release) }; } }
基准测试结果
我的CPU为Ryzen 3700X。测试中启动16个线程,全部竞争2个锁,结果如下:
> cargo run --release -- 16 2 10000 100 Options { n_threads: 16, n_locks: 2, n_ops: 10000, n_rounds: 100, } spinlock (amd) avg 6.242695ms min 4.784792ms max 10.356368ms spinlock (mcs) avg 19.968031ms min 13.980298ms max 60.338753ms
可见MCS锁性能明显差于简易自旋锁。即使调整参数为16线程+32锁以模拟低竞争场景,仍未观察到MCS锁的性能优势。
请问是我的实现存在问题,还是MCS锁本身性能不佳?
内容的提问来源于stack exchange,提问作者QuarticCat
相关产品推荐
相关产品推荐

