Keystroke has asked for the wisdom of the Perl Monks concerning the following question:

I'm writing a cgi script and wanting to fork to do some lengthy processing. When I do a fork, the parent process is waiting for the child to finish because of (I assume) open files from a module that is in the child subroutine (same file). Rather than move the child to a different file and executing that file to get past this, I would like to keep it all in one file. It's a small script. My question is, how can I find and close all open file handles in the parent process? Performing an exit doesn't seem to do the trick. The required modules are in the child's branch of the fork and are Spreadsheet::ParseExcel and Spreadsheet::WriteExcel if that helps. Or am I way off of my reasoning of why the parent is waiting? Thanks.
  • Comment on Parent waiting on child when using modules

Replies are listed 'Best First'.
Re: Parent waiting on child when using modules
by pearlie (Sexton) on Dec 02, 2004 at 06:28 UTC
    Hello, Can you please elaborate on your question a little? If you fork() without ever waiting on your children, you will accumulate zombies.
Re: Parent waiting on child when using modules
by BUU (Prior) on Dec 02, 2004 at 09:30 UTC
    You are probably confused. Perl won't wait on open filehandles and if you are indeed forking properly, it won't wait on children either. A better problem description and/or actual code would help.
      Well I know I'm confused. Here is a test case that will show my problem. When this is run as a cgi script, the browser will wait until the child exits before finishing. If I comment out the two Spreadsheet modules it works perfectly and finishes without waiting on the child process.
      use strict; go(); sub go { $| = 1; $SIG{CHLD} = 'IGNORE'; close STDIN; my $pid = fork; if (!defined($pid)) { print "Content-type: text/plain\n\n"; print "Could not fork!\n"; exit; } elsif ($pid) { print "Content-type: text/plain\n\n"; print "PARENT = $$, KID = $pid\n" . localtime(time); close STDERR; close STDOUT; close STDIN; exit; } else { close STDIN; close STDOUT; close STDERR; use Spreadsheet::ParseExcel; use Spreadsheet::WriteExcel; open(STDERR, ">test.err"); sleep(10); open(OUT,">>test") or die(); print OUT "\nKID(me) = $$ " . localtime(time); close OUT; exit; } }
        I tracked the problem down
        Spreadsheet::WriteExcel uses
        Spreadsheet::WriteExcel::Workbook which uses
        Spreadsheet::WriteExcel::Worksheet which uses
        Spreadsheet::WriteExcel::Formula which uses
        Parse::RecDescent

        and confirmed that Parse::RecDecent duplicates STDERR to 3 filehandles.

        This fixes the problem I have.
        close Parse::RecDecent::ERROR;
        close Parse::RecDecent::TRACECONTEXT;
        close Parse::RecDecent::CONTEXT;

        Is there any way to track down open filehandles in perl?