Brian Candler
7/5/2005 9:01:00 AM
On Tue, Jul 05, 2005 at 08:24:51AM +0900, Joel VanderWerf wrote:
> > I have a smell application from which I wish to display a file using an
> > external helper programme.
> >
> > Lets say
> > app = the external programme
> > file = the file to be displayed
> >
> > I've tried
> >
> > system(app, file)
> >
> > This works but it blocks my application. How can I fire up the helper
> > application in the background?
>
> Thread.new {system(app, file)}
>
> if all you want to do is start the process and you don't care about the
> output or return value. Otherwise, see Ara's solutions.
It's worth mentioning that all that the system() call does is:
1. fork
2. exec (in child)
3. wait for child to terminate (in parent)
So a lower-level way to get what you want, without using Ruby threads, is:
pid = Process.fork do
exec(app, file)
end
and later on, you may wish to do
Process.waitpid(pid)
to reap the child and get its exit status. If it dies before then, it will
remain in the process table as a 'zombie' until you reap it or the parent
terminates. The Ruby thread solution effectively cleans up the child
automatically at the end for you.
If you want app to run as a daemon and never worry about when it terminates
(even if the Ruby program terminates first), then you can fork twice, run
the application in the grandchild, and the child terminates immediately:
pid = Process.fork do
Process.fork do
# normally you would redirect STDIN/STDOUT/STDERR here
exec(app, file)
end
exit
end
Process.waitpid(pid)
... continue here
I like being in full control like this, because system() hides the fact that
it is doing a fork, and fork can result in wierdness. For example, any
'atexit' script you've previously defined will run in both parent and child.
'teardown' scripts in Test::Unit can end up being called in both parent and
child. And so on.
Regards,
Brian.