lib/thread.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #               thread.rb - thread support classes
   3  #                       $Date: 2002/08/27 08:31:08 $
   4  #                       by Yukihiro Matsumoto <matz@netlab.co.jp>
   5  #
   6  # Copyright (C) 2001  Yukihiro Matsumoto
   7  # Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
   8  # Copyright (C) 2000  Information-technology Promotion Agency, Japan
   9  #
  10  
  11  unless defined? Thread
  12    fail "Thread not available for this ruby interpreter"
  13  end
  14  
  15  unless defined? ThreadError
  16    class ThreadError<StandardError
  17    end
  18  end
  19  
  20  if $DEBUG
  21    Thread.abort_on_exception = true
  22  end
  23  
  24  def Thread.exclusive
  25    _old = Thread.critical
  26    begin
  27      Thread.critical = true
  28      return yield
  29    ensure
  30      Thread.critical = _old
  31    end
  32  end
  33  
  34  class Mutex
  35    def initialize
  36      @waiting = []
  37      @locked = false;
  38      @waiting.taint              # enable tainted comunication
  39      self.taint
  40    end
  41  
  42    def locked?
  43      @locked
  44    end
  45  
  46    def try_lock
  47      result = false
  48      Thread.critical = true
  49      unless @locked
  50        @locked = true
  51        result = true
  52      end
  53      Thread.critical = false
  54      result
  55    end
  56  
  57    def lock
  58      while (Thread.critical = true; @locked)
  59        @waiting.push Thread.current
  60        Thread.stop
  61      end
  62      @locked = true
  63      Thread.critical = false
  64      self
  65    end
  66  
  67    def unlock
  68      return unless @locked
  69      Thread.critical = true
  70      @locked = false
  71      begin
  72        t = @waiting.shift
  73        t.wakeup if t
  74      rescue ThreadError
  75        retry
  76      end
  77      Thread.critical = false
  78      begin
  79        t.run if t
  80      rescue ThreadError
  81      end
  82      self
  83    end
  84  
  85    def synchronize
  86      lock
  87      begin
  88        yield
  89      ensure
  90        unlock
  91      end
  92    end
  93  
  94    def exclusive_unlock
  95      return unless @locked
  96      Thread.exclusive do
  97        @locked = false
  98        begin
  99          t = @waiting.shift
 100          t.wakeup if t
 101        rescue ThreadError
 102          retry
 103        end
 104        yield
 105      end
 106      self
 107    end
 108  end
 109  
 110  class ConditionVariable
 111    def initialize
 112      @waiters = []
 113    end
 114    
 115    def wait(mutex)
 116      mutex.exclusive_unlock do
 117        @waiters.push(Thread.current)
 118        Thread.stop
 119      end
 120      mutex.lock
 121    end
 122    
 123    def signal
 124      begin
 125        t = @waiters.shift
 126        t.run if t
 127      rescue ThreadError
 128        retry
 129      end
 130    end
 131      
 132    def broadcast
 133      waiters0 = nil
 134      Thread.exclusive do
 135        waiters0 = @waiters.dup
 136        @waiters.clear
 137      end
 138      for t in waiters0
 139        begin
 140          t.run
 141        rescue ThreadError
 142        end
 143      end
 144    end
 145  end
 146  
 147  class Queue
 148    def initialize
 149      @que = []
 150      @waiting = []
 151      @que.taint          # enable tainted comunication
 152      @waiting.taint
 153      self.taint
 154    end
 155  
 156    def push(obj)
 157      Thread.critical = true
 158      @que.push obj
 159      begin
 160        t = @waiting.shift
 161        t.wakeup if t
 162      rescue ThreadError
 163        retry
 164      ensure
 165        Thread.critical = false
 166      end
 167      begin
 168        t.run if t
 169      rescue ThreadError
 170      end
 171    end
 172    alias << push
 173    alias enq push
 174  
 175    def pop(non_block=false)
 176      while (Thread.critical = true; @que.empty?)
 177        raise ThreadError, "queue empty" if non_block
 178        @waiting.push Thread.current
 179        Thread.stop
 180      end
 181      @que.shift
 182    ensure
 183      Thread.critical = false
 184    end
 185    alias shift pop
 186    alias deq pop
 187  
 188    def empty?
 189      @que.empty?
 190    end
 191  
 192    def clear
 193      @que.clear
 194    end
 195  
 196    def length
 197      @que.length
 198    end
 199    def size
 200      length
 201    end
 202  
 203    def num_waiting
 204      @waiting.size
 205    end
 206  end
 207  
 208  class SizedQueue<Queue
 209    def initialize(max)
 210      raise ArgumentError, "queue size must be positive" unless max > 0
 211      @max = max
 212      @queue_wait = []
 213      @queue_wait.taint           # enable tainted comunication
 214      super()
 215    end
 216  
 217    def max
 218      @max
 219    end
 220  
 221    def max=(max)
 222      Thread.critical = true
 223      if max <= @max
 224        @max = max
 225        Thread.critical = false
 226      else
 227        diff = max - @max
 228        @max = max
 229        Thread.critical = false
 230        diff.times do
 231          begin
 232            t = @queue_wait.shift
 233            t.run if t
 234          rescue ThreadError
 235            retry
 236          end
 237        end
 238      end
 239      max
 240    end
 241  
 242    def push(obj)
 243      Thread.critical = true
 244      while @que.length >= @max
 245        @queue_wait.push Thread.current
 246        Thread.stop
 247        Thread.critical = true
 248      end
 249      super
 250    end
 251    alias << push
 252    alias enq push
 253  
 254    def pop(*args)
 255      retval = super
 256      Thread.critical = true
 257      if @que.length < @max
 258        begin
 259          t = @queue_wait.shift
 260          t.wakeup if t
 261        rescue ThreadError
 262          retry
 263        ensure
 264          Thread.critical = false
 265        end
 266        begin
 267          t.run if t
 268        rescue ThreadError
 269        end
 270      end
 271      retval
 272    end
 273    alias shift pop
 274    alias deq pop
 275  
 276    def num_waiting
 277      @waiting.size + @queue_wait.size
 278    end
 279  end