我有一个提供条件变量的同步队列。
当数据添加到队列时,该条件变量发出信号。
我有5个帖子:
Thread.new do
loop do
@queue.synchronize {
cond.wait_until { @queue.has_data? || @queue.finished? }
}
# some processing code that can also call @queue.enqueue
end
end
然后我这样做:
@queue.enqueue some_data
@threads.each(&:join)
MyQueue#enqueue
看起来像这样:
def enqueue(data)
synchronize do
@pending << v unless queued?(data) || processed?(data) || processing?(data)
data_cond.signal
end
end
def finished?
@started && @processing.empty? && @pending.empty?
end
def has_data?
!@pending.empty?
end
我开始#join
deadlock detected
这究竟是如何导致死锁的,以及如何修复它?
答案 0 :(得分:2)
我想知道这是否存在 所有 线程在 条件变量上被阻止的问题,并没有可用于排队数据的线程,这将释放其他线程。
根据此代码中的评论:
Thread.new do
loop do
@queue.synchronize {
cond.wait_until { @queue.has_data? || @queue.finished? }
}
# some processing code that can also call @queue.enqueue
end
end
你的评论中提到“一些也可以调用@ queue.enqueue的处理代码”,这是唯一一个调用@queue.enqueue
的地方吗?如果是这样,那么所有的线程都将在条件变量上被阻塞,并且没有人能够到达能够调用enqueue的点。我确信Ruby可以检测到所有线程都锁定在同一个实体上,并且没有一个可以释放它,因此死锁。
如果确实有一个单独的线程只排队(这将是典型的生产者/消费者情况),请确保它不会等待条件变量,这也可能导致死锁。
答案 1 :(得分:1)
帮助你有点困难,因为你只发布代码片段......
你应该试试work_queue宝石,或者至少看看source code。
答案 2 :(得分:0)
没有必要等待has_data? ||完了吗?在同步块中。代码应如下所示:
Thread.new do
loop do
cond.wait_until { @queue.has_data? || @queue.finished? }
enq = nil
@queue.synchronize {
enq = @queue.pop
}
# some processing code that can also call @queue.enqueue
end
end
在这种情况下,只有在使用队列内容进行操作时才会锁定其他线程。您需要做的是同步队列状态更改,如完成
更好的解决方案是使用互斥锁包装所有线程关键变量,例如rails中的here。它会使代码变慢,因为它消除了同时变量访问。