1# 2# thwait.rb - thread synchronization class 3# $Release Version: 0.9 $ 4# $Revision: 1.3 $ 5# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd.) 6 7require "thread.rb" 8require "e2mmap.rb" 9 10# 11# This class watches for termination of multiple threads. Basic functionality 12# (wait until specified threads have terminated) can be accessed through the 13# class method ThreadsWait::all_waits. Finer control can be gained using 14# instance methods. 15# 16# Example: 17# 18# ThreadsWait.all_wait(thr1, thr2, ...) do |t| 19# STDERR.puts "Thread #{t} has terminated." 20# end 21# 22# 23# th = ThreadsWait.new(thread1,...) 24# th.next_wait # next one to be done 25# 26# 27class ThreadsWait 28 RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-' 29 30 extend Exception2MessageMapper 31 def_exception("ErrNoWaitingThread", "No threads for waiting.") 32 def_exception("ErrNoFinishedThread", "No finished threads.") 33 34 # 35 # Waits until all specified threads have terminated. If a block is provided, 36 # it is executed for each thread as they terminate. 37 # 38 def ThreadsWait.all_waits(*threads) # :yield: thread 39 tw = ThreadsWait.new(*threads) 40 if block_given? 41 tw.all_waits do |th| 42 yield th 43 end 44 else 45 tw.all_waits 46 end 47 end 48 49 # 50 # Creates a ThreadsWait object, specifying the threads to wait on. 51 # Non-blocking. 52 # 53 def initialize(*threads) 54 @threads = [] 55 @wait_queue = Queue.new 56 join_nowait(*threads) unless threads.empty? 57 end 58 59 # Returns the array of threads that have not terminated yet. 60 attr :threads 61 62 # 63 # Returns +true+ if there are no threads in the pool still running. 64 # 65 def empty? 66 @threads.empty? 67 end 68 69 # 70 # Returns +true+ if any thread has terminated and is ready to be collected. 71 # 72 def finished? 73 !@wait_queue.empty? 74 end 75 76 # 77 # Waits for specified threads to terminate, and returns when one of 78 # the threads terminated. 79 # 80 def join(*threads) 81 join_nowait(*threads) 82 next_wait 83 end 84 85 # 86 # Specifies the threads that this object will wait for, but does not actually 87 # wait. 88 # 89 def join_nowait(*threads) 90 threads.flatten! 91 @threads.concat threads 92 for th in threads 93 Thread.start(th) do |t| 94 begin 95 t.join 96 ensure 97 @wait_queue.push t 98 end 99 end 100 end 101 end 102 103 # 104 # Waits until any of the specified threads has terminated, and returns the one 105 # that does. 106 # 107 # If there is no thread to wait, raises +ErrNoWaitingThread+. If +nonblock+ 108 # is true, and there is no terminated thread, raises +ErrNoFinishedThread+. 109 # 110 def next_wait(nonblock = nil) 111 ThreadsWait.fail ErrNoWaitingThread if @threads.empty? 112 begin 113 @threads.delete(th = @wait_queue.pop(nonblock)) 114 th 115 rescue ThreadError 116 ThreadsWait.fail ErrNoFinishedThread 117 end 118 end 119 120 # 121 # Waits until all of the specified threads are terminated. If a block is 122 # supplied for the method, it is executed for each thread termination. 123 # 124 # Raises exceptions in the same manner as +next_wait+. 125 # 126 def all_waits 127 until @threads.empty? 128 th = next_wait 129 yield th if block_given? 130 end 131 end 132end 133 134## 135# An alias for ThreadsWait from thwait.rb 136 137ThWait = ThreadsWait 138 139# Documentation comments: 140# - Source of documentation is evenly split between Nutshell, existing 141# comments, and my own rephrasing. 142# - I'm not particularly confident that the comments are all exactly correct. 143