1.65、使用条件变量的时候需要注意什么?
条件变量本身无“记忆”功能,可能发生“丢失唤醒”问题
signal
(或notify_one
)时,没有线程处于等待状态,那么该信号会丢失,后续的wait
不会捕获到这个信号,导致线程可能永远阻塞。因此,必须保证等待线程先进入等待状态,或者通过条件判断避免遗漏唤醒。
必须在持有互斥锁的情况下检查条件并调用wait
,保证操作的原子性
条件的判断和等待必须在同一把锁保护下完成,防止竞态条件。通常使用std::unique_lock<std::mutex>
,并结合cv.wait(lock, predicate)
的形式,内部会自动释放和重新获取锁,同时避免虚假唤醒带来的错误。
修改条件变量关联的共享状态时,也必须持锁操作
即使共享变量是原子类型,也应在持锁状态下修改,以保证修改对等待线程的正确可见性,避免同步问题。
防止虚假唤醒(spurious wakeup)
条件变量等待可能被非预期唤醒,因此必须在wait
返回后重新检查条件(使用带谓词的wait
重载自动完成此操作),确保线程只有在条件满足时才继续执行。
通知操作(notify_one
或notify_all
)时不必持锁,但修改条件状态时必须持锁
通知线程在修改完共享条件后调用notify
,通知等待线程重新检查条件。通知时不强制要求持锁,但为了保证状态修改的同步,修改状态时必须持锁。
总结来说,正确使用条件变量的最佳实践是:
- • 在持锁状态下判断条件,若条件不满足则调用
wait
,等待时自动释放锁,唤醒后重新加锁并检查条件。 - • 修改条件状态时必须持锁,并在修改后调用
notify_one
或notify_all
通知等待线程。 - • 理解条件变量无记忆特性,避免信号丢失,确保等待线程先于通知线程进入等待状态或通过条件判断规避。
- • 始终使用带谓词的
wait
接口防止虚假唤醒导致的错误执行。
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/1419
文章版权归作者所有,未经允许请勿转载。
THE END