Thread lockup in ruby with Soap4r

209 views Asked by At

This is related to a question I asked here: Thread Locking in Ruby (use of soap4r and QT)

However it is particular to one part of that question and is supported by a simpler example. The test code is:

require 'rubygems'
require 'thread'
require 'soap/rpc/standaloneserver'

class SOAPServer < SOAP::RPC::StandaloneServer

    def initialize(* args)
        super
        # Exposed methods
        add_method(self, 'test', 'x', 'y')
    end

    def test(x, y)
        return x + y
    end
end


myServer = SOAPServer.new('monitorservice', 'urn:ruby:MonitorService', 'localhost',         4004)

Thread.new do
    puts 'Starting web services'
    myServer.start
    puts 'Ending web services'
end

sleep(4)

#Thread.new do
    testnum = 0
    while testnum < 4000 do
        testnum += 1
        puts myServer.test(0,testnum)
        sleep(2)
    end
#end

puts myServer.test(0,4001)
puts myServer.test(0,4002)
puts myServer.test(0,4003)
puts myServer.test(0,4004)
gets

When I run this with the thread commented out everything runs along fine. However, once the thread is put in the process hangs. I poked into Webrick and found that the stop occurs here (the puts are, of course, mine):

while @status == :Running
      begin
        puts "1.1"
        if svrs = IO.select(@listeners, nil, nil, 2.0)
          svrs[0].each{|svr|
        puts "-+-"
            @tokens.pop          # blocks while no token is there.
            if sock = accept_client(svr)
              th = start_thread(sock, &block)
              th[:WEBrickThread] = true
              thgroup.add(th)
            else
              @tokens.push(nil)
            end
          }
        end
        puts ".+."

When run with the thread NOT commented out I get something like this: Starting web services

1.1
.+.
1.1
4001
4002
4003
4004
1
.+.
1.1
2

There are 2 answers

0
nick On BEST ANSWER

The trailing gets blocks Ruby's IO. I'm not sure why. If it is replaced with pretty much anything the program works. I used a sleeping loop:

loop do
    sleep 1
end

ADDED: I should note that I also get strange behavior with sleep based on the sleep increment. In the end I abandoned Ruby since the threading behavior was too wonky.

0
liwp On

If the problem is caused by the gets() call and the purpose of the gets() call in your code is to prevent the Ruby interpreter from exiting, you can replace it with Thread.join() calls for each thread that you create. Join() will block until that thread has finished executing and therefore it'll prevent the Ruby interpreter from exiting.

E.g.:

t1 = Thread.new do
    puts 'Starting web services'
    myServer.start
    puts 'Ending web services'
end

t2 = ...
...

t1.join
t2.join

Alternatively, if you can join() only one of the threads if there is a single thread that controls the execution of the application, and the other threads will be killed on exit.