仅双线程场景下该自定义二进制互斥锁实现是否能保证永远有效?
结论
你的自定义锁实现存在逻辑漏洞,哪怕是严格的单写单读双线程场景,也不能保证永远正常工作,当前运行正常只是该漏洞的触发概率较低。
核心问题:逻辑竞态
存在完全合法的CPU调度时序会触发读写同时进入临界区,步骤如下:
- 读线程进入
acquireAccessLock,先将accessLockRequest置为true - 读线程判断
while (modifyLockRequest),此时写线程还没设置修改锁请求,循环条件不满足,退出循环 - 就在读线程准备执行
accessLock = true的前一刻,写线程进入acquireModifyLock:- 写线程先将
modifyLockRequest置为true - 写线程判断循环条件
accessLockRequest && accessLock,此时accessLock还没被读线程赋值,仍然是false,循环条件不满足,写线程直接退出循环拿到修改锁,开始修改vector
- 写线程先将
- 此时读线程继续执行,将
accessLock置为true,拿到读锁开始访问vector
到这一步就出现了读写同时操作vector的情况,直接触发未定义行为,轻则读到脏数据,重则触发SIGABRT崩溃。
其他潜在问题
- 你的锁设计没有显式控制内存序,虽然当前
std::atomic默认使用的std::memory_order_seq_cst内存序刚好能满足需求,但如果后续为了性能调整为更宽松的内存序,很容易出现读写线程看不到对方修改的问题。 - 即使没有删除操作,vector插入如果触发扩容,会涉及内存重新分配、元素拷贝、旧内存释放,如果此时读线程正在访问旧内存地址,会直接触发野指针访问,建议提前给vector预分配足够的容量,避免运行时扩容。
优化方案建议
如果你想要低开销的同步方案,单写单读场景可以选择更成熟的实现:
- 用
std::atomic_flag实现自旋锁:逻辑简单无漏洞,开销和你当前的实现接近,完全可以替代std::mutex满足百万次加解锁的性能需求。 - 如果后续需要扩展多线程读,可以改用
std::shared_mutex,读写分离的设计比普通互斥锁更适合读多写少的场景。
内容的提问来源于stack exchange,提问作者acarturk
相关产品推荐
相关产品推荐

