Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class QueueWithTimeout
- def initialize
- @mutex = Mutex.new
- @queue = []
- @recieved = ConditionVariable.new
- end
- def <<(x)
- @mutex.synchronize do
- @queue << x
- @recieved.signal
- puts "Signalled"
- end
- end
- def pop(non_block = false)
- pop_with_timeout(non_block ? 0 : nil)
- end
- def pop_with_timeout(timeout = nil)
- printf "pop_with_timeout in #{Thread.current[:id]}\n"
- @mutex.synchronize do
- if @queue.empty?
- puts "Queue empty in #{Thread.current[:id]}"
- @recieved.wait(@mutex, timeout) if timeout != 0
- puts "Resuming in #{Thread.current[:id]}"
- #if we're still empty after the timeout, raise exception
- raise ThreadError, "queue empty" if @queue.empty?
- end
- @queue.shift
- end
- end
- end
- queue = QueueWithTimeout.new
- Thread.abort_on_exception = true
- 10.times do |i|
- Thread.new do
- Thread.current[:id] = i
- loop do
- queue.pop_with_timeout(100000.0) # a long timeout, that we'll never reach
- puts i
- end
- end
- end
- loop do
- queue << "random stuff"
- puts "pushed"
- end
- __END__
- # Example program output (comments on the right after the # char)
- $ ruby condition_variable_signal.rb
- pop_with_timeout in 2
- Queue empty in 2
- pop_with_timeout in 0
- pop_with_timeout in 1
- Signalled # @recieved.signal called, note that other threads run before condition_variable is actually resumed on line 75
- pop_with_timeout in 9
- pop_with_timeout in 4
- pop_with_timeout in 5
- pop_with_timeout in 6
- pop_with_timeout in 7
- pop_with_timeout in 8
- pop_with_timeout in 3
- pushed
- 0 # Thread 0 popped the value. Note that thread 0 never called @recieved.wait(...)!
- pop_with_timeout in 0
- Resuming in 2 # Thread 2 wakes up and finds empty queue.
- Queue empty in 1
- Queue empty in 9
- Queue empty in 4
- condition_variable_signal.rb:28:in `block in pop_with_timeout': queue empty (ThreadError)
- from condition_variable_signal.rb:22:in `synchronize'
- from condition_variable_signal.rb:22:in `pop_with_timeout'
- from condition_variable_signal.rb:43:in `block (3 levels) in <main>'
- from condition_variable_signal.rb:42:in `loop'
- from condition_variable_signal.rb:42:in `block (2 levels) in <main>'
- Conclusions
- - I couldn't reproduce "spurious wakeup" behavior.
- - I was able to find/reproduce a bug related to interesting `ConditionVariable#signal` behavior, see program output with comments above.
- - I do agree using `while` loop with a condition variable predicate solves the problem.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement