daily pastebin goal
51%
SHARE
TWEET

Untitled

a guest Jul 30th, 2017 68 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. class QueueWithTimeout
  2.   def initialize
  3.     @mutex = Mutex.new
  4.     @queue = []
  5.     @recieved = ConditionVariable.new
  6.   end
  7.  
  8.   def <<(x)
  9.     @mutex.synchronize do
  10.       @queue << x
  11.       @recieved.signal
  12.       puts "Signalled"
  13.     end
  14.   end
  15.  
  16.   def pop(non_block = false)
  17.     pop_with_timeout(non_block ? 0 : nil)
  18.   end
  19.  
  20.   def pop_with_timeout(timeout = nil)
  21.     printf "pop_with_timeout in #{Thread.current[:id]}\n"
  22.     @mutex.synchronize do
  23.       if @queue.empty?
  24.         puts "Queue empty in #{Thread.current[:id]}"
  25.         @recieved.wait(@mutex, timeout) if timeout != 0
  26.         puts "Resuming in #{Thread.current[:id]}"
  27.         #if we're still empty after the timeout, raise exception
  28.         raise ThreadError, "queue empty" if @queue.empty?
  29.       end
  30.       @queue.shift
  31.     end
  32.   end
  33. end
  34.  
  35. queue = QueueWithTimeout.new
  36.  
  37. Thread.abort_on_exception = true
  38.  
  39. 10.times do |i|
  40.   Thread.new do
  41.     Thread.current[:id] = i
  42.     loop do
  43.       queue.pop_with_timeout(100000.0) # a long timeout, that we'll never reach
  44.       puts i
  45.     end
  46.   end
  47. end
  48.  
  49. loop do
  50.   queue << "random stuff"
  51.   puts "pushed"
  52. end
  53.  
  54.  
  55.  
  56. __END__
  57. # Example program output (comments on the right after the # char)
  58.  
  59. $ ruby condition_variable_signal.rb    
  60. pop_with_timeout in 2    
  61. Queue empty in 2        
  62. pop_with_timeout in 0    
  63. pop_with_timeout in 1    
  64. Signalled                # @recieved.signal called, note that other threads run before condition_variable is actually resumed on line 75
  65. pop_with_timeout in 9    
  66. pop_with_timeout in 4    
  67. pop_with_timeout in 5    
  68. pop_with_timeout in 6    
  69. pop_with_timeout in 7    
  70. pop_with_timeout in 8    
  71. pop_with_timeout in 3    
  72. pushed                  
  73. 0                        # Thread 0 popped the value. Note that thread 0 never called @recieved.wait(...)!
  74. pop_with_timeout in 0    
  75. Resuming in 2            # Thread 2 wakes up and finds empty queue.
  76. Queue empty in 1        
  77. Queue empty in 9        
  78. Queue empty in 4        
  79. condition_variable_signal.rb:28:in `block in pop_with_timeout': queue empty (ThreadError)            
  80.        from condition_variable_signal.rb:22:in `synchronize'                                        
  81.        from condition_variable_signal.rb:22:in `pop_with_timeout'                                  
  82.         from condition_variable_signal.rb:43:in `block (3 levels) in <main>'                        
  83.        from condition_variable_signal.rb:42:in `loop'                                              
  84.        from condition_variable_signal.rb:42:in `block (2 levels) in <main>'  
  85.          
  86.          
  87.          
  88. Conclusions
  89.          
  90. - I couldn't reproduce "spurious wakeup" behavior.
  91. - I was able to find/reproduce a bug related to interesting `ConditionVariable#signal` behavior, see program output with comments above.
  92. - I do agree using `while` loop with a condition variable predicate solves the problem.
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top