I have a synchronized queue that provides a condition variable.
That condition variable signals when data is added to the queue.
I have 5 threads:
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
Then I do:
@queue.enqueue some_data
@threads.each(&:join)
MyQueue#enqueue looks like this:
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
And I get on #join
deadlock detected
How exactly does this cause a deadlock and how would one fix it?
I wonder if this is a problem that all of the threads are blocked on the same condition variable, and there isnt a thread available to enqueue data, which would release the other threads.
Based on the comment in this code:
Your comment that mentions “some processing code that can also call @queue.enqueue”, is this the only place where
@queue.enqueueis called? If so, then all of the threads will be blocked on the condition variable and none will be able to get to the point to be able to call enqueue. Im sure Ruby can detect that all threads are locked on the same entity and none are available to release it, thus deadlock.If you do indeed have a separate thread that only enqueues (which would be a typical producer/consumer situation) make sure that it doesnt also wait on the condition variable, which could also cause deadlock.