能否用std::atomic::wait替代互斥锁?是否存在死锁风险?
关于std::atomic::wait的死锁风险疑问
我在阅读StackOverflow的《C20 mutex with atomic wait》和《Can std::atomic be used sometimes instead of std::mutex in C?》两个问题后产生了疑问,想了解调用std::atomic::wait函数同步代码是否安全。不少资料显示可以使用该函数,但我认为其可能存在死锁风险,示例代码如下:
#include <atomic> #include <iostream> #include <thread> #include <vector> std::atomic<bool> lock = false; void go(){ bool expected = false; while(!lock.compare_exchange_strong(expected, true)) { lock.wait(true); expected = false; } std::cout << "Sincronizado" << std::endl; lock = false; lock.notify_all(); } int main() { std::vector<std::thread> threads; threads.reserve(2); for(int i = 0; i < 2; i++) threads.emplace_back(go); for(auto& thread : threads) thread.join(); }
目前这段代码看似正常,但设想以下场景:
线程1:
- 成功通过
while(!lock.compare_exchange_strong(expected, true))竞争 - 执行到
lock = false;之前被抢占 - 线程1被抢占
线程2:
while(!lock.compare_exchange_strong(expected, true))竞争失败- 开始执行
lock.wait(true); - 在该函数内部(底层使用Futex)检查lock为true
- 仍在该函数内,调用
FUTEX_WAIT阻塞前被抢占
线程1:
- 恢复执行,将lock设为false
- 调用
lock.notify_all();通知所有等待线程
线程2:
- 恢复执行,开始执行
FUTEX_WAIT阻塞 - 是否会发生死锁?
请问该场景是否可能发生,还是我多虑了?
你多虑了,这个场景不会发生死锁。
原因在于std::atomic::wait的底层实现(比如Linux上的futex机制)在真正将线程阻塞前,会原子性地再次检查原子变量的值是否与预期值匹配。具体到你的场景:
当线程2恢复执行并准备进入阻塞时,FUTEX_WAIT操作会先原子性检查lock的当前值是否为true——此时lock已经被线程1设为false,不匹配预期值,因此wait会直接返回,不会阻塞线程2。
之后线程2会重置expected = false,再次执行compare_exchange_strong,此时lock是false,CAS操作会成功,线程2就能进入临界区执行后续代码。
另外需要注意:即使存在“虚假唤醒”(无通知情况下的唤醒),代码中的while循环也能保证逻辑正确性——这也是wait通常要配合循环使用的核心原因。
内容的提问来源于stack exchange,提问作者Lucas Paixão
相关产品推荐
相关产品推荐

