2025年条件变量是什么(条件变量使用场景)

条件变量是什么(条件变量使用场景)作者 钓雪 链接 https www zhihu com question answer 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 需要 condition 变量的原因本质上就是程序执行顺序的不确定性 管程 monitor 只是保证了同一时刻只有一个进程在管程内活动

大家好,我是讯享网,很高兴认识大家。



作者:钓雪 链接:https://www.zhihu.com/question//answer/ 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 需要condition变量的原因本质上就是程序执行顺序的不确定性.管程(monitor)只是保证了同一时刻只有一个进程在管程内活动,即管程内定义的操作在同一时刻只被一个进程调用(由编译器实现).但是这样并不能保证进程以设计的顺序执行,因此需要设置condition变量,让进入管程而无法继续执行的进程阻塞自己.也可以这么说,由于程执行顺序的不确定性,进程在entry序列中的顺序并不一定是我们想要的,而condition变量就是用来操作entry序列的.有了condition变量,我们就可以让在自己前驱进程之前提前进入管程的进程挂起自己,退回到entry序列中重新排队.具体来说: 以生产者-消费者问题(也称有限缓冲问题)为例, 如果我们不使用信号量(semaphore)而简单的用整形变量count来记录buffer中的数据项数目, 用系统调用sleep()阻塞进程 和 wakeup() 唤醒进程 程序如下#define TRUE 1 #define MAX 100 void insert_item(int); int remove_item(); int count = 0; void producer() { 
讯享网</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> item; </span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)">(TRUE) { item </span>=<span style="color: rgba(0, 0, 0, 1)"> produce_item(); </span><span style="color: rgba(0, 0, 255, 1)">if</span>( count ==<span style="color: rgba(0, 0, 0, 1)"> MAX ) sleep(); insert_item(item); count </span>+= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">if</span>( count == <span style="color: rgba(128, 0, 128, 1)">1</span>) wakeup(consumer); <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">buffer由空变非空后唤醒挂起的消费者</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> } 
}
讯享网
void consumer() {
</span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> item; </span><span style="color: rgba(0, 0, 255, 1)">while</span><span style="color: rgba(0, 0, 0, 1)">(TRUE) { </span><span style="color: rgba(0, 0, 255, 1)">if</span>( count == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)"> ) sleep(); item </span>=<span style="color: rgba(0, 0, 0, 1)"> remove_item(); count </span>-= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">buffer由满变不满后唤醒生产者</span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">if</span>( count == MAX - <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)"> ) wakeup(producer); consume_item(item); } 
} 这样写的问题在于 我们不能保证 count 变量的互斥访问.如果producer在consumersleep之前发送wakeup信号便会导致错误,程序执行顺序如下1. 消费者 在检查到count == 0而未休眠2. 生产者 执行 count += 1 并且向 消费者发送 wakeup信号,3. 由于此时消费者并未sleep,wakeup信号丢失4. 之后消费者执行sleep休眠5. 生产者不断生产而消费者休眠直到buffer填满6. 生产者消费者都休眠,无法相互唤醒如果我们将访问count变量的过程写入管程中,就可以使两个进程对count进行互斥访问,从而解决这个问题.但是,管程并不知道编程者的逻辑,它并不能在生产者在count == MAX时挂起自己,也不能在 count == MAX - 1 时唤醒生产者,这时就需要使用条件变量.我们定义管程#define MAX 100 / 定义管程 PC / monitor PC {
讯享网</span><span style="color: rgba(0, 0, 255, 1)">int</span> count = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 我们使用条件变量full 表示被填满的buffer, empty 表示空的buffer </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> conditon full, empty; </span><span style="color: rgba(0, 0, 255, 1)">void</span> insert(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> item) { </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 当buffer满的时候,我们在full上将插入操作阻塞 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">if</span> ( count == MAX ) wait(&amp;<span style="color: rgba(0, 0, 0, 1)">full); insert_item(item); count </span>+= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 当buffer不空的时候,我们在empty上唤醒取出操作 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">if</span> ( count == MAX -<span style="color: rgba(128, 0, 128, 1)">1</span> ) signal(&amp;<span style="color: rgba(0, 0, 0, 1)">empty); } </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> remove() { </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 当buffer空的时候,我们在empty上将取出操作阻塞 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">if</span>( count == <span style="color: rgba(128, 0, 128, 1)">0</span> ) wait(&amp;<span style="color: rgba(0, 0, 0, 1)">empty); remove_item(item); count </span>-= <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 当buffer不满的时候,我们在full上唤醒插入操作 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> item; </span><span style="color: rgba(0, 0, 255, 1)">if</span>( count == MAX - <span style="color: rgba(128, 0, 128, 1)">1</span>) signal(&amp;<span style="color: rgba(0, 0, 0, 1)">full); } 
}
</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> producer() { </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> item; item </span>=<span style="color: rgba(0, 0, 0, 1)"> produce_item(); </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">调用管程中的函数 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> PC.insert(item); } </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> consumer() { </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> item; </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">调用管程中的函数 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)"> item </span>=<span style="color: rgba(0, 0, 0, 1)"> PC.remove(); consumer_item(); } 
* 注意 以上代码 用类似于C的代码写成 ,但 C语言并不支持管程 JAVA 支持管程 在method前加sychronized 关键字 可以保证在一个线程调用 synchronized method时 不允许其他线程调用该对象中其他synchronized method *这样以来, 由于管程保证内部内部操作的互斥性,操作就不会wait()的前一刻被signal(),从而不会发生生产者和消费者都被阻塞而无法相互唤醒的情况了.同时我们的生产者和消费者也可以在恰当的时候阻塞自己.条件变量不止存在于管程中,在多线程库中也是普遍存在的.Unix的多线程库Pthread中也使用条件变量协调进程的同步.

讯享网

小讯
上一篇 2025-06-14 22:24
下一篇 2025-06-06 15:22

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/153244.html