1998-01-16 15:13:05 +03:00
|
|
|
#
|
1999-01-20 07:59:39 +03:00
|
|
|
# thwait.rb - thread synchronization class
|
|
|
|
# $Release Version: 0.9 $
|
|
|
|
# $Revision: 1.3 $
|
|
|
|
# $Date: 1998/06/26 03:19:34 $
|
|
|
|
# by Keiju ISHITSUKA(Nihpon Rational Software Co.,Ltd.)
|
1998-01-16 15:13:05 +03:00
|
|
|
#
|
|
|
|
# --
|
1999-01-20 07:59:39 +03:00
|
|
|
# feature:
|
|
|
|
# provides synchronization for multiple threads.
|
1998-01-16 15:13:05 +03:00
|
|
|
#
|
1999-01-20 07:59:39 +03:00
|
|
|
# class methods:
|
|
|
|
# * ThreadsWait.all_waits(thread1,...)
|
|
|
|
# waits until all of specified threads are terminated.
|
|
|
|
# if a block is supplied for the method, evaluates it for
|
|
|
|
# each thread termination.
|
|
|
|
# * th = ThreadsWait.new(thread1,...)
|
|
|
|
# creates synchronization object, specifying thread(s) to wait.
|
|
|
|
#
|
|
|
|
# methods:
|
|
|
|
# * th.threads
|
|
|
|
# list threads to be synchronized
|
|
|
|
# * th.empty?
|
|
|
|
# is there any thread to be synchronized.
|
|
|
|
# * th.finished?
|
|
|
|
# is there already terminated thread.
|
|
|
|
# * th.join(thread1,...)
|
|
|
|
# wait for specified thread(s).
|
|
|
|
# * th.join_nowait(threa1,...)
|
|
|
|
# specifies thread(s) to wait. non-blocking.
|
|
|
|
# * th.next_wait
|
|
|
|
# waits until any of specified threads is terminated.
|
|
|
|
# * th.all_waits
|
|
|
|
# waits until all of specified threads are terminated.
|
|
|
|
# if a block is supplied for the method, evaluates it for
|
|
|
|
# each thread termination.
|
1998-01-16 15:13:05 +03:00
|
|
|
#
|
|
|
|
|
|
|
|
require "thread.rb"
|
|
|
|
require "e2mmap.rb"
|
|
|
|
|
|
|
|
class ThreadsWait
|
1999-01-20 07:59:39 +03:00
|
|
|
RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-'
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
Exception2MessageMapper.extend_to(binding)
|
1999-01-20 07:59:39 +03:00
|
|
|
def_exception("ErrNoWaitingThread", "No threads for waiting.")
|
2000-09-25 13:15:08 +04:00
|
|
|
def_exception("ErrNoFinishedThread", "No finished threads.")
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
def ThreadsWait.all_waits(*threads)
|
1999-01-20 07:59:39 +03:00
|
|
|
tw = ThreadsWait.new(*threads)
|
2000-06-28 12:31:35 +04:00
|
|
|
if block_given?
|
2000-09-25 13:15:08 +04:00
|
|
|
tw.all_waits do |th|
|
1998-01-16 15:13:05 +03:00
|
|
|
yield th
|
|
|
|
end
|
|
|
|
else
|
|
|
|
tw.all_waits
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(*threads)
|
|
|
|
@threads = []
|
|
|
|
@wait_queue = Queue.new
|
|
|
|
join_nowait(*threads) unless threads.empty?
|
|
|
|
end
|
|
|
|
|
|
|
|
# accessing
|
1999-01-20 07:59:39 +03:00
|
|
|
# threads - list threads to be synchronized
|
1998-01-16 15:13:05 +03:00
|
|
|
attr :threads
|
|
|
|
|
|
|
|
# testing
|
|
|
|
# empty?
|
|
|
|
# finished?
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
# is there any thread to be synchronized.
|
1998-01-16 15:13:05 +03:00
|
|
|
def empty?
|
|
|
|
@threads.empty?
|
|
|
|
end
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
# is there already terminated thread.
|
1998-01-16 15:13:05 +03:00
|
|
|
def finished?
|
|
|
|
!@wait_queue.empty?
|
|
|
|
end
|
|
|
|
|
|
|
|
# main process:
|
|
|
|
# join
|
|
|
|
# join_nowait
|
|
|
|
# next_wait
|
|
|
|
# all_wait
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
# adds thread(s) to join, waits for any of waiting threads to terminate.
|
1998-01-16 15:13:05 +03:00
|
|
|
def join(*threads)
|
|
|
|
join_nowait(*threads)
|
|
|
|
next_wait
|
|
|
|
end
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
# adds thread(s) to join, no wait.
|
1998-01-16 15:13:05 +03:00
|
|
|
def join_nowait(*threads)
|
2000-09-25 13:15:08 +04:00
|
|
|
threads.flatten!
|
|
|
|
@threads.concat threads
|
1998-01-16 15:13:05 +03:00
|
|
|
for th in threads
|
2000-09-25 13:15:08 +04:00
|
|
|
Thread.start(th) do |t|
|
|
|
|
t.join
|
|
|
|
@wait_queue.push t
|
1998-01-16 15:13:05 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
# waits for any of waiting threads to terminate
|
|
|
|
# if there is no thread to wait, raises ErrNoWaitingThread.
|
|
|
|
# if `nonblock' is true, and there is no terminated thread,
|
|
|
|
# raises ErrNoFinishedThread.
|
1998-01-16 15:13:05 +03:00
|
|
|
def next_wait(nonblock = nil)
|
1999-01-20 07:59:39 +03:00
|
|
|
ThreadsWait.fail ErrNoWaitingThread if @threads.empty?
|
|
|
|
begin
|
|
|
|
@threads.delete(th = @wait_queue.pop(nonblock))
|
|
|
|
th
|
|
|
|
rescue ThreadError
|
2000-09-20 13:16:32 +04:00
|
|
|
ThreadsWait.fail ErrNoFinishedThread
|
1999-01-20 07:59:39 +03:00
|
|
|
end
|
1998-01-16 15:13:05 +03:00
|
|
|
end
|
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
# waits until all of specified threads are terminated.
|
|
|
|
# if a block is supplied for the method, evaluates it for
|
|
|
|
# each thread termination.
|
1998-01-16 15:13:05 +03:00
|
|
|
def all_waits
|
|
|
|
until @threads.empty?
|
|
|
|
th = next_wait
|
2000-06-28 12:31:35 +04:00
|
|
|
yield th if block_given?
|
1998-01-16 15:13:05 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
1999-01-20 07:59:39 +03:00
|
|
|
|
|
|
|
ThWait = ThreadsWait
|