信号量是否包含条件变量?wait与signal机制是否类同条件变量?
信号量 vs 管程中的条件变量:别把同步机制搞混啦
兄弟,先给你拍板定个结论:信号量本身并不自带条件变量,你觉得它的wait()和signal()跟条件变量的操作类似,其实是表象,本质差得远呢。
咱们拆开说清楚:
1. 两者的本质完全不同
信号量就是个带原子操作的整数,它的核心是资源计数:
wait()(有的地方叫P())是把计数减1,如果计数变成负数,当前进程就阻塞在这个信号量的等待队列里;signal()(有的地方叫V())是把计数加1,如果之前有进程阻塞,就唤醒其中一个。
整个逻辑围绕“资源有没有剩余”这个计数来转,没有额外的“条件”概念。
管程里的条件变量,是依附于管程(或者说互斥锁)的同步工具,它的核心是等待逻辑条件成立:
- 当进程进入管程后,发现某个逻辑条件不满足(比如生产者消费者模型里,缓冲区满了,生产者没法放),就调用条件变量的
wait(),这时候它会主动释放管程的锁,然后阻塞在这个条件变量的等待队列里; - 当其他进程在管程里改变了这个条件(比如消费者取走了一个数据,缓冲区不满了),就调用条件变量的
signal(),唤醒等待的进程,被唤醒的进程会重新竞争管程的锁,然后继续执行。
这里的“条件”是程序员自己定义的逻辑状态(比如缓冲区是否为空、是否已满),条件变量只是用来传递“条件变了”的通知。
- 当进程进入管程后,发现某个逻辑条件不满足(比如生产者消费者模型里,缓冲区满了,生产者没法放),就调用条件变量的
2. 看似一致的流程,底层逻辑天差地别
你觉得流程像,是因为两者都有“阻塞等待”和“唤醒”的动作,但触发原因完全不一样:
- 信号量的阻塞,是因为资源计数不够用了——比如初始化信号量为0,调用
wait()就直接阻塞,直到有人调用signal()把计数拉回正数; - 条件变量的阻塞,是因为你要等的逻辑条件不成立——哪怕管程里的资源足够,只要条件没满足,你就得等着。
举个例子:假设我们用管程实现生产者消费者,条件变量是not_full和not_empty。生产者进来后,发现缓冲区满了(逻辑条件不满足),就wait(not_full);消费者取走一个后,signal(not_full),这时候生产者才会被唤醒,重新检查缓冲区是否真的不满(因为可能有多个生产者被唤醒),然后继续生产。
如果用信号量的话,我们会用两个信号量empty(空缓冲区数量)和full(满缓冲区数量),生产者wait(empty),消费者signal(empty)——这里的wait是直接等“空缓冲区”这个资源计数,没有额外的逻辑条件检查。
3. 为什么说管程才有条件变量?
因为条件变量的设计就是和管程绑定的:它必须在互斥的环境下使用(管程本身就是互斥进入的),wait()时必须释放锁,signal()后唤醒的进程要重新获取锁——这些逻辑信号量本身是不具备的,信号量的wait()和signal()只是操作计数,和锁没有强制绑定关系。
总结一下:信号量是靠计数来同步,条件变量是靠逻辑条件的通知来同步,俩不是一回事哦。
内容的提问来源于stack exchange,提问作者Spade
相关产品推荐
相关产品推荐

