Re: A tricky problem about Process.wait and popen
- From: Robert Klemme <bob.news@xxxxxxx>
- Date: Sun, 14 May 2006 13:01:18 +0200
First of all please don't post the same message several times.
uncutstone wrote:
I think I already have understanded all of these. But a understanding
doesn't mean a solution.
Let me give the problem I want to solve.
There is a parent process and a fixed number of child processes. Parent
process is responsible for forking a fixed number of child processes
using IO.popen and then wait for any child process exits. Whenever a
child process complete its task , it will write the result in pipe and
signal the parent process "mission complete" and then exits. When
parent get the signal, it will read correspondant pipe to get result
and then creating a new child process .
Try the implementation I suggested. The IO created by IO.popen will not signal EOF before the child terminated. So just use read or readlines to read the pipe's contents until you get everything (= process terminated). You can then evaluate it as you see fit. (see the suggested code I posted earlier).
If the result returned by the child process is small, pipe doesn't get
full, it works well.
You must not rely on this. Increasing the pipe's size is not an option as you still have a limit. Your process is responsible for reading the pipe in order to prevent the writer from blocking.
But if the result is big and pipe gets full, the child get blocked and
signal cannot send to parent process.
Let me make it simple.
1.Multiple child process want to return result to parent process via
pipe.
2. Parent need a mechanism similar to unix select() to get notification
from child process when it completes its task.
The code is something like this:
main.rb
processNum = 10
pipes = Hash.new
numOfProcessRunning = 0
loop do
apipe = IO.popen("ruby child.rb","w+")
cpid = apipe.gets.strip.to_i
pipes[cpid] = apipe
numOfProcessRunning += 1
if numOfProcessRunning >= processNum
cpid = Process.wait
apipe = pipes[cpid]
apipe.each { |line|
#.... , get the result
}
apipe.close
pipes.delete(cpid)
numOfProcessRunning -= 1
end
end
This looks overly complex. You could do something like this:
PARALLEL = 10
threads = (1..PARALLEL).map do |i|
Thread.new i do |count|
IO.popen("ruby -e 'puts \"child #{count}\"'") do |io|
res = io.read
puts "Child #{count} returned #{res.inspect}"
end
end
end
puts "Started"
threads.each {|th| th.join}
puts "Terminated"
child.rb:
puts Process.pid
$stdout.flush
#..... , do something, then
puts result
Btw, if your child processes are Ruby processes you can use fork with a block:
PARALLEL = 10
threads = (1..PARALLEL).map do |i|
Thread.new i do |count|
read, write = IO.pipe
cpid = fork do
read.close
write.puts "I'm child #{count}"
write.close
end
write.close
res = read.read
puts "Child #{count} with PID #{cpid} returned #{res.inspect}"
end
end
puts "Started"
threads.each {|th| th.join}
puts "Terminated"
If you need to communicate more complex information between child and parent you can use Marshal on the pipe:
PARALLEL = 10
threads = (1..PARALLEL).map do |i|
Thread.new i do |count|
read, write = IO.pipe
cpid = fork do
# in child process
read.close
Marshal.dump({:result => "I'm child #{count}"}, write)
write.close
end
# in parent process
write.close
res = Marshal.load(read)
puts "Child #{count} with PID #{cpid} returned #{res.inspect}"
end
end
puts "Started"
threads.each {|th| th.join}
puts "Terminated"
These examples with explicitly created pipe work the same as the popen approach, i.e. the parent thread blocks until the pipe reaches EOF which in turn happens when the child exits.
Kind regards
robert
.
- Follow-Ups:
- Re: A tricky problem about Process.wait and popen
- From: uncutstone
- Re: A tricky problem about Process.wait and popen
- References:
- A tricky problem about Process.wait and popen
- From: uncutstone
- Re: A tricky problem about Process.wait and popen
- From: uncutstone
- Re: A tricky problem about Process.wait and popen
- From: Gonald
- Re: A tricky problem about Process.wait and popen
- From: Robert Klemme
- Re: A tricky problem about Process.wait and popen
- From: uncutstone
- A tricky problem about Process.wait and popen
- Prev by Date: thread safty
- Next by Date: Re: thread safty
- Previous by thread: Re: A tricky problem about Process.wait and popen
- Next by thread: Re: A tricky problem about Process.wait and popen
- Index(es):
Relevant Pages
|
|