Hmm.  I'm not a thread pro, but I'll give it a shot.
I don't think it's necessarily a problem with backtick, but with the 
code itself :)

first off

Justin Johnson wrote:
> Hello,
> 
> I'm using the ThreadPool class as defined in the Ruby Cookbook, recipe
> 20.7 and running on Windows XP with the One Click installer of Ruby
> 1.8.6 patch level 0.  Normally it works fine.  However, whenever I call
> a command using backticks I get a deadlock.  The script I'm running is
> below, followed by the output.  To see it succeed, comment out the
> backtick line and uncomment out the system line.
> 
> Does anyone know what the problem is?
> 
> Thanks,
> Justin
> 
> ##### BEGIN FILE ######
> require 'thread'
> 
> class ThreadPool
>   def initialize(max_size)
>     @pool = []
>     @max_size = max_size
>     @pool_mutex = Mutex.new
>     @pool_cv = ConditionVariable.new
>   end
> #---
>   def dispatch(*args)
>     Thread.new do
>       # Wait for space in the pool.
>       @pool_mutex.synchronize do
>         while @pool.size >= @max_size
>           print "Pool is full; waiting to run #{args.join(',')}...\n" if
> $DEBUG
>           # Sleep until some other thread calls @pool_cv.signal.
>           @pool_cv.wait(@pool_mutex)
>         end
>       end
> #---


>       @pool << Thread.current

The above line should be within the synchronize (above), or it might 
spawn more than @max_size threads (I think).
Replace with
      @pool_mutex.synchronize do
        while @pool.size >= @max_size
          print "Pool is full; waiting to run #{args.join(',')}...\n" if 
$DEBUG
          # Sleep until some other thread calls @pool_cv.signal.
          @pool_cv.wait(@pool_mutex)
        end
        @pool << Thread.current
      end

>       begin
>         yield(*args)
>       rescue => e
>         exception(self, e, *args)
>       ensure
>         @pool_mutex.synchronize do

In reality you don't need to synchronize here, as the @pool size/add to 
is synchronized elsewhere.  Taking this synch out may introduce new 
problems, but...I'm not sure what they are :)
My question is if the wait within the shutdown function will 'suck' 
signals away from processes, decreasing the number that can go at a 
time, if all are at the 'wait' phase.  Perhaps rethinking this code 
would be nice :)

-Roger


>           # Remove the thread from the pool.
>           @pool.delete(Thread.current)
>           # Signal the next waiting thread that there's a space in the
> pool.
>           @pool_cv.signal
>         end

>       end
>     end
>   end
> 
>   def shutdown
>     @pool_mutex.synchronize { @pool_cv.wait(@pool_mutex) until
> @pool.empty? }
>   end
> 
>   def exception(thread, exception, *original_args)
>     # Subclass this method to handle an exception within a thread.
>     puts "Exception in thread #{thread}: #{exception}"
>   end
> end
> #---
> 
> 
> 
> pool = ThreadPool.new 2
> begin
>   1.upto(200) do |i|
>     pool.dispatch do
>       puts "Job #{i} started."
>       `dir c:\\winnt > NUL`
>       #system("dir c:\\winnt > NUL")
>       puts "Job #{i} stopped."
>     end
>   end
> ensure
>   pool.shutdown
> end
> ##### END FILE ######
> 
> 
> ##### BEGIN OUTPUT ######
> C:\temp>ruby thread_test.rb
> Job 1 started.
> Job 2 started.
> Job 1 stopped.
> Job 2 stopped.
> Job 3 started.
> Job 6 started.
> Job 5 started.
> Job 4 started.
> Job 3 stopped.
> Job 6 stopped.
> Job 5 stopped.
> Job 4 stopped.
> deadlock 0x2b45008: sleep:-  - thread_test.rb:18
> deadlock 0x2b450d0: sleep:-  - thread_test.rb:18
> deadlock 0x2b45198: sleep:-  - thread_test.rb:18
> deadlock 0x2b45260: sleep:-  - thread_test.rb:18
> ... Skip many similar lines ...
> deadlock 0x2b5627c: sleep:-  - thread_test.rb:28
> deadlock 0x2b5636c: sleep:-  - thread_test.rb:28
> deadlock 0x27ac748: sleep:- (main) - thread_test.rb:39
> thread_test.rb:39:in `wait': Thread(0x27ac748): deadlock (fatal)
>         from thread_test.rb:39:in `shutdown'
>         from thread_test.rb:39:in `synchronize'
>         from thread_test.rb:39:in `shutdown'
>         from thread_test.rb:62
> 
> C:\temp>
> ##### END OUTPUT ######

There may also (I'm not positive about this), be a way that multiple 
signals may then occur very quickly, and only one processed.  Another 
possible problem, too.

GL
-Roger
-- 
Posted via http://www.ruby-forum.com/.