Advertisement
Guest User

Untitled

a guest
Jul 30th, 2017
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 2.88 KB | None | 0 0
  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.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement