获取信号量值后调用wait()或先判断再调用wait()为何存在问题?
嘿,这两个问题本质上都是**竞态条件(Race Condition)**在搞鬼,咱们一个个拆解清楚:
问题1:为什么获取信号量的值后再调用wait()会存在问题?
信号量的核心作用之一就是提供原子性的操作保障——比如wait()(也就是经典的P操作)本身是一个原子动作:它会原子地完成「检查信号量值是否大于0 → 如果是就减1 → 否则阻塞等待」这一整套逻辑。
但如果你把操作拆成「先调用getValue(&sem)获取值,再调用wait(&sem)」,这两步之间就出现了一个可被打断的时间窗口,彻底破坏了原子性。举个实际场景的例子:
- 假设信号量
sem初始值是1,有线程A和B同时在竞争它 - 线程A先调用
getValue(&sem),拿到结果1,正准备执行wait(&sem) - 就在这个间隙,线程B抢先执行了
wait(&sem),把信号量的值从1改成了0 - 等线程A再执行
wait(&sem)时,信号量已经是0了,只能被迫阻塞——但A本来以为自己能顺利获取到信号量,这就导致了完全不符合预期的行为。
说白了,你把一个原子的“检查+操作”拆成了两步,给其他线程留了“插队”修改信号量的机会,等于亲手废掉了信号量最核心的原子性保护。
问题2:为什么先检查信号量值>0再调用wait()会存在问题?
你写的这段代码if (getValue(&sem)>0){ wait(&sem); },问题根源和上面完全一致——「检查信号量值」和「调用wait」这两个动作不是原子的,也就是业界常说的「检查-执行」竞态条件。
还是用例子说明:
- 信号量初始值为1,线程A和B都走到了
if判断的步骤 - 线程A判断
getValue(&sem)>0为真,进入代码块,但还没来得及调用wait(&sem) - 线程B此时也执行
if判断,因为A还没修改信号量,所以判断结果也是真,同样进入代码块 - 线程B先执行
wait(&sem),把信号量的值改成了0 - 线程A接着执行
wait(&sem),此时信号量已经是0,A会被阻塞(或者触发错误,取决于信号量的实现)
这就完全违背了你写这个if判断的初衷——你本来想“只有当信号量可用时才调用wait,避免阻塞”,但结果却是两个线程都“误以为”信号量可用,最终其中一个还是会阻塞。
这里要划重点:信号量的wait()操作本身已经内置了原子的「检查+减1」逻辑,你额外加的这个if判断不仅多此一举,还亲手引入了竞态条件。正确的做法就是直接调用wait(&sem),让信号量自己处理原子性的逻辑。
内容的提问来源于stack exchange,提问作者Programmer
相关产品推荐
相关产品推荐

