我们可以通过以给定顺序启动线程来解决问题,并且可能在两者之间进行一些睡眠以强制执行同步.但那只是推迟了真正的问题.
我将代码重写为经典的producer-consumer problem:
require 'thread'queue = []mutex = Mutex.newresource = ConditionVariable.newthreads = []threads << Thread.new do 5.times do |i| mutex.synchronize do resource.wait(mutex) value = queue.pop print "consumed #{value}\n" end endendthreads << Thread.new do 5.times do |i| mutex.synchronize do queue << i print "#{i} produced\n" resource.signal end sleep(1) #simulate expense endendthreads.each(&:join)
有时你会得到这个(但并不总是):
0 produced1 producedconsumed 02 producedconsumed 13 producedconsumed 24 producedconsumed 3producer-consumer.rb:30:in `join': deadlock detected (fatal) from producer-consumer.rb:30:in `each' from producer-consumer.rb:30:in `<main>'
什么是正确的解决方案?
解决方法 问题在于,正如您之前评论的那样,只有在您可以保证消费者线程在程序开始时首先获取互斥锁时,此方法才有效.如果不是这种情况,则会发生死锁,因为生成器线程的第一个resource.signal将在使用者线程尚未等待资源时发送.因此,第一个resource.signal基本上不会执行任何 *** 作,因此您最终会调用resource.signal 4次(因为第一个丢失),而resource.wait则调用5次.这意味着消费者将永远等待,并发生死锁.幸运的是,我们可以通过仅允许消费者线程开始等待来解决这个问题,如果没有更多的即时工作可用.
require 'thread'queue = []mutex = Mutex.newresource = ConditionVariable.newthreads = []threads << Thread.new do 5.times do |i| mutex.synchronize do if queue.empty? resource.wait(mutex) end value = queue.pop print "consumed #{value}\n" end endendthreads << Thread.new do 5.times do |i| mutex.synchronize do queue << i print "#{i} produced\n" resource.signal end sleep(1) #simulate expense endendthreads.each(&:join)总结
以上是内存溢出为你收集整理的ruby – 如何使用条件变量?全部内容,希望文章能够帮你解决ruby – 如何使用条件变量?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)