dRuby question

I am trying to write a client/server application using dRuby drb-2.0b1 onWin
XP(Pro)
ruby 1.7.3 (2002-11-17) [i386-mswin32]

Got it working in a single threaded mode (see code below).
But need some help to get it multi-threaded.

I have commented out the multi-threading part because it does not work.
Any help will be highly appreciated.
Thanks,

— shanko

==========================================

Server code

require 'drb’
require ‘timeout’

STDOUT.sync = true

class TstSrvr
def initialize
@work_threads = []
end

def time_now
    "It is:  " + Time.now.to_s
end

def work_request(owner = "", work_id = 0)
    return "Sorry, owner cannot be empty string" if owner == ""
    return "Sorry #{owner}, invalid work_id" if work_id < 1
    ret  = "Working on [" + work_id.to_s + "] from " + owner
    #t = Thread.new {
        sleep(0.1)
        puts "Start #{owner}:#{work_id}> " + `echo %TIME%`
        puts `ping localhost`
        puts "Stop  #{owner}:#{work_id}> " + `echo %TIME%`
    # }
    #@work_threads << t
    #t.join
    ret
end

def check_work(owner = "", work_id = 0)

# Stub for checking if the work is over

end

def bye(msg="")
   puts msg

   #p @work_threads
   #@work_threads.each { |t| t.join }

   Thread.new {sleep(0.1); exit(1)}
   nil
end

end

srvObj = TstSrvr.new

begin

    DRb.start_service("druby://localhost:5555",srvObj)
    DRb.thread.join

rescue RuntimeError
puts 'Got runtime error: '
puts $!
DRb.stop_service
retry
end

==========================================

Client Code

require ‘drb’

STDOUT.sync = true

begin
DRb.start_service
cliObj = DRbObject.new(nil,“druby://localhost:5555”)

2.times { |i|
    puts cliObj.time_now
    puts cliObj.work_request("_shanko",i+1)
    sleep(2)
}

# cliObj.bye('Bye Bye')

rescue RuntimeError
puts 'Connect error:'
puts $!
end

==========================================

Code to stop the server

require ‘drb’

cliObj = DRb::DRbObject.new(nil,“druby://localhost:5555”)
cliObj.bye(‘Bye Bye’)

well…

I’m not very experienced in this kind of things but i’m in a mood to
learn…

i tried your code multi-threaded and it DOES work (at least without errors
or exceptions)…

the thing is - your code features several calls to the OS - the echo and the
ping commands

ruby threads are (i think) ruby-internal so if ruby does a call to the OS,
ruby can’t act (let another thread do it’s work) until it gets control back
from the OS. so your original code really was multithreaded but it seemed
linear for ruby threads are not really threads to the OS…
quote from the rubybook of the pragmaticprogrammers on this matter:

And if some thread happens to make
a call to the operating system that takes
a long time to complete, all threads will
hang until the interpreter gets control back.

i modified your code (replaced the OS-calls) - and it IS multithreaded as
you will see when you try it.

the client.rb is the same as yours, also the exit.rb

···

#server.rb
require ‘drb’
require ‘timeout’

STDOUT.sync = true

class TstSrvr
def initialize
@work_threads =
end

def time_now
    "It is:  " + Time.now.to_s
end

def work_request(owner = "", work_id = 0)

return “Sorry, owner cannot be empty string” if owner == “”
return “Sorry #{owner}, invalid work_id” if work_id < 1
ret = “Working on [” + work_id.to_s + “] from " + owner
t = Thread.new {
100.times { |i|
puts(work_id.to_s+”: "+i.to_s)
sleep(0.1)
}
}
@work_threads = @work_threads << t
ret
end

def check_work(owner = "", work_id = 0)

# Stub for checking if the work is over

end

def bye(msg="")
   puts msg

   p @work_threads
   @work_threads.each { |t| t.join }

   Thread.new {sleep(0.1); exit(1)}
   nil
end

end

srvObj = TstSrvr.new

begin

    DRb.start_service("druby://localhost:5555",srvObj)
    DRb.thread.join

rescue RuntimeError
puts 'Got runtime error: ’
puts $!
DRb.stop_service
retry
end
----- end of code -------

regards, patrick

using ruby 1.6.8 (pragmaticprogrammer installer 168-8) on winXPpro

“Shashank Date” sdate@kc.rr.com writes:

I have commented out the multi-threading part because it does not work.

What do you mean by “Does not work”? Can you be more specific?

I uncommented the commented code and it worked as I expected. Of
course, since I’m running it on linux, I have to make some
modifications:

        puts `ping localhost`
puts `ping -c 5 localhost` # ping 5 times, then quit.
   t.join
I removed this line because it may not be what you want.  You
spawned another thread and put it into the work_threads list
because that thread potentially take a long time to do (for
example, pinging 100 times). Thus, you probably don't want to join
with it so soon (join meaning wait for it to finish before
continuing to the next instruction).

So, what exactly are you trying to accomplish?

YS.

“pat zes” jonnypichler@gmx.net writes:

ruby threads are (i think) ruby-internal so if ruby does a call to the OS,
ruby can’t act (let another thread do it’s work) until it gets control back
from the OS.

The threading in the official ruby implementations is implemented in
pure user-space threading with pre-emptive scheduling. Conceptually,
if you spawn two threads, and one of them is blocked by a syscall, the
other thread execution should not be affected (blocked). The current
implementation does this by employing a regularly occuring signal that
interrupts whatever the process is doing and hand back the control to
the scheduler, allowing the scheduler to run another thread.

YS.

“Yohanes Santoso” ysantoso@jenny-gnome.dyndns.org wrote in message

What do you mean by “Does not work”? Can you be more specific?

The second thread does not start till the first thread is done, effectively
defeating the purpose of multi-threading.

puts `ping -c 5 localhost` # ping 5 times, then quit.

Yes, I tried that (on Windows) to get the output shown above, like so:

puts `ping -n 5 localhost`
   t.join
I removed this line because it may not be what you want.

Sorry, my mistake ! It was commented out in my original original code for
the same reasons you mentioned … just forgot to take it out.

So, what exactly are you trying to accomplish?

Thanks for showing interest. This is what I want to accomplish:

I have a requestor application which will generate work requests which take
considerable time (even hours !) to complete. The drb server that I am
trying to write (whose first draft you have seen) should accept these work
request and dispatch them to the least busy machine for execution (all
machines are Windows based). Mean while, the requestor may do other things
and at regular intervals check (poll) for its work status. While doing those
“other things” the requestor may abort (user may kill the process). In which
case I want the drb server (dispatcher) to recognize that fact (hey, that
guy has not polled for his work request, so must no longer be interested)
and kill the appropriate work thread. The client code you have seen is just
a dummy code I am using to simulate the scenario and get a feel for the
whole thing.

Hope this is clear enough. If not please let me know …

Thanks again.

– shanko

Hi,

“pat zes” jonnypichler@gmx.net wrote in message

the thing is - your code features several calls to the OS - the echo and
the
ping commands

Well, in that case try this simple script:

--------------------------------

th =
3.times { |i|
th << Thread.new(i) {
sleep(1)
puts "#{i} Start> " + echo %TIME%
ping -n 15 localhost
puts "#{i} Stop> " + echo %TIME%
}
}

th.each {|t| t.join }

···

#--------------------------------

And if you open up TaskManager and look at the “Processes” tab sorted by
Image name,
you will see three ping processes actually running for a while. You (may)
get output like this:

1 Start>  2:24:04.84
0 Start>  2:24:04.85
2 Start>  2:24:04.86
2 Stop>  2:24:19.27
0 Stop>  2:24:19.29
1 Stop>  2:24:19.28

Which is kind of what I expected with drb too.

ruby threads are (i think) ruby-internal so if ruby does a call to the OS,
ruby can’t act (let another thread do it’s work) until it gets control
back
from the OS. so your original code really was multithreaded but it seemed
linear for ruby threads are not really threads to the OS…

Please see Yohanes Santoso’s response.

quote from the rubybook of the pragmaticprogrammers on this matter:

And if some thread happens to make
a call to the operating system that takes
a long time to complete, all threads will
hang until the interpreter gets control back.

Hmmm… will have to ponder on that !

i modified your code (replaced the OS-calls) - and it IS multithreaded as
you will see when you try it.

Yes, that works like i want it to.

regards, patrick

Thanks, patrick.
– shanko

using ruby 1.6.8 (pragmaticprogrammer installer 168-8) on winXPpro

Could it be that we are trying it on different versions of Ruby.
Let me see what happens on 1.8.

P.S> Did you get the article I emailed you?

“Shashank Date” sdate@kc.rr.com wrote in message

What do you mean by “Does not work”? Can you be more specific?

The second thread does not start till the first thread is done,
effectively
defeating the purpose of multi-threading.

Got this working now. All I had to do was replace back-quoted commands with
a system call !
So doing:

`ping -n 10 localhost`

was blocking the thread until done, while as

system("ping -n 10 localhost")

was not. Makes me believe that there is something different between the two
methods.
Not surprising because back-quoting allows you to capture the output in a
string variable
but system does not.

– shanko