Hi Eric

On Mon, 2005-08-29 at 19:09, Eric Hodel wrote:
> On 29 Aug 2005, at 08:57, Andrew S. Townley wrote:
[snip]
> ThreadGroup, ThreadGroup, ThreadGroup.  Create a ThreadGroup for each  
> thread you spawn so you can see who is spawning the extra threads.

Hmmm... I think I might use a ThreadGroup, no? ;)

> > Also, I've looked at this from a number of different angles, but it
> > appears to be no way to create a normal thread pool with Ruby.

Ok, this was just selective stupidity on my part.  Apologies.  After
digging out my Doug Lea Concurrent Java book, I saw what I was
forgetting...

> What do you want?

Something like this (actually, it was straightforward enough once I
thought about it a little):

$ cat tpool.rb
require 'thread'
 
class ThreadPool
  def initialize(size)
    @work = Queue.new
    @workers = []
    @group = ThreadGroup.new
    @shutdown = false
    @sh_mutex = Mutex.new
    size.times do
      @workers << t = Thread.new { Thread.stop; thread_work };
      @group.add(t)
    end
    @monitor = Thread.new do
      Thread.stop
      loop do
        @sh_mutex.synchronize { Thread.current.terminate if @shutdown }
        sleep(1)
      end
    end
  end
 
  def <<(runnable)
    @work << runnable
    self
  end
 
  def thread_work
    loop do
      @sh_mutex.synchronize do
        if @shutdown
          puts "#{Thread.current} stopping";
          Thread.current.terminate
        end
      end
      puts "#{Thread.current.inspect} is one of #{@work.num_waiting} waiting for work"
      job = @work.deq
      begin
        job.run if job != nil
        Thread.pass
      rescue => e
        puts e
        next
      end
    end
  end
 
  def start
    @workers.each { |w| w.run }
    @monitor.run
  end
 
  def join
    @monitor.join
  end
 
  def shutdown(wait = true)
    @sh_mutex.synchronize { @shutdown = true }
    @workers.each { |w| w.join if w.alive? } if wait
  end
 
  attr_reader :group
end
 
class Runnable
  def initialize(*args, &block)
    @block = block
  end
 
  def run
    @block.call
  end
end
 
pool = ThreadPool.new(8)
 
pool.start
job1 = Runnable.new do
  3.times { puts "#{Thread.current.inspect} - hello"; sleep(rand*3) }
end
 
vagrant = Runnable.new { raise "broken" }
 
pool << job1 << vagrant << job1 << job1 << job1 << job1
pool << vagrant << job1 << job1 << vagrant << vagrant << job1
 
Thread.new { t = rand*2; puts "sleeping #{t}"; sleep(t); pool.shutdown(false) }
pool.join
pool.shutdown
 
puts "Thread group"
pool.group.list.each { |w| puts w.inspect }
 
puts "Thread.list"
Thread.list.each { |w| puts w.inspect }


***************************************************************************************************
The information in this email is confidential and may be legally privileged.  Access to this email by anyone other than the intended addressee is unauthorized.  If you are not the intended recipient of this message, any review, disclosure, copying, distribution, retention, or any action taken or omitted to be taken in reliance on it is prohibited and may be unlawful.  If you are not the intended recipient, please reply to or forward a copy of this message to the sender and delete the message, any attachments, and any copies thereof from your system.
***************************************************************************************************