You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

手写读者优先的读写自旋锁(允许写饥饿)是否正确?是否存在数据竞争?

读者优先读写自旋锁实现的正确性与数据竞争分析

这个手写的读者优先读写自旋锁实现不正确,存在严重的逻辑漏洞和数据竞争问题,具体问题如下:

一、写锁获取逻辑彻底失效

写操作的锁获取逻辑是:

uint32_t expect = 0;
while(!lock.compare_exchange_strong(expect, 1 << 31));

这里的CAS操作要求lock的值必须等于expect(初始为0)才能设置写位(1 << 31)。但读者优先的场景下,正常逻辑应该是允许已有读者时写操作等待,而非只有无任何读者/写者时才能获取写锁。更致命的是:一旦有读者持有读锁(lock的值为正整数),第一次CAS失败后,expect会被更新为当前lock的非零值,后续循环里没有重置expect为0,导致CAS永远无法成功,写操作会彻底卡死,永远拿不到锁。

二、读操作引发死锁风险

读操作的流程是先执行lock.fetch_add(1)增加读者计数,再检查写位:

lock.fetch_add(1);
while(lock.load() & (1 << 31));

这里存在时间窗口:在fetch_add(1)完成后、lock.load()检查写位之前,若写操作发起锁获取(即便写锁逻辑修复),此时读者已把计数加1,写操作因看到lock不为0无法获取锁,而读者因看到写位被设置进入循环等待,最终形成死锁——读者等写锁释放,写锁等所有读者释放。

三、明确存在数据竞争

  • 对共享资源val的读写没有正确的互斥保障:写操作的push_back和读操作的val[i]之间,没有通过锁建立正确的happens-before关系。比如读者在等待写位时已完成fetch_add(1),此时写操作可能正在修改val,后续读者读取val[i]时无法保证看到写操作的最新结果,存在数据竞争。
  • 读操作的fetch_add和load是两个独立的原子操作,中间无原子性保障,导致上述死锁场景,本质也是同步逻辑错误引发的竞态问题。

四、写解锁操作的潜在风险

写操作用lock.fetch_xor(1 << 31)解锁,虽然在写锁正确获取的情况下(即lock值为1 << 31),这个操作能正确清除写位,但如果前面的锁获取逻辑错误导致lock值异常(比如混入读者计数),这个xor操作会破坏读者计数,引发更复杂的同步问题。

内容的提问来源于stack exchange,提问作者touyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:35:19