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

I am basically trying to launch process in the background, and exit from my perl script only when all the child processes launched by the system command get completed. In c-shell scripts I used to use the wait command but for some reason the waitpid function doesn't work the same.

here's my sample code

eval 'exec /usr/bin/perl -w -S $ ${1+"$@"}' if 0; use strict; use PWPerl; use POSIX "sys_wait_h"; use POSIX "signal_h"; my @wkslist = ("ws3133", "ws3735", "ws31175", "ws193243", "ws2023", "ws5445", "ws24157", "ws31205",); my $rsh_cmd = "rshto -to 60"; my $wks; foreach $wks (@wkslist) { print "rshing to $wks \n"; pwsystem("$rsh_cmd $wks ls &"); } waitpid(-1,0); print "all done\n";

Replies are listed 'Best First'.
Re: Background process using a system call
by maverick (Curate) on Aug 20, 2001 at 22:30 UTC
    I don't think you can use waitpid in conjunction with system in that way. Try doing something like this instead:
    my @pids; foreach my $wks (@wkslist) { my $pid = fork; if ($pid == 0) { # child print "rshing to $wks \n"; system("$rsh_cmd $wks ls"); exit; } else { push(@pids,$pid); } } foreach my $pid (@pids) { waitpid($pid,0); }
    The child that you forked (which you now have the pid of) will terminate when your system command does, thus emulating the behavior you're looking for.

    /\/\averick
    perl -l -e "eval pack('h*','072796e6470272f2c5f2c5166756279636b672');"

      You've got the parent/child comments the wrong way round, you may as well use exec instead of the system/exit pair, and why not catch all of those return codes from rsh?

      local (%rc, $running); # turn off stdout buffering $| = 1; # catch return codes local $SIG{CHLD} = sub { $rc{wait()} = $?; --$running; }; foreach my $wks (@wkslist) { if ( my $pid = fork() ) { # parent ++$running; } else { # child print "rshing to $wks\n"; exec($rsh_cmd, $wks, "ls"); } } sleep while ($running);

      I have an old snippet which you may find useful at Run some commands in parallel

      Are you writing a program to execute arbitrary commands on multiple hosts at the same time? If so, check back in a day or two and I'll have the script I use posted that packs in a few features.

        ummm...according to "perldoc perlfunc" my parent/child comments aren't backwards.

        Fork Does a fork(2) system call to create a new process running the same program at the same point. It returns the child pid to the parent process, `0' to the child process, or `undef' if the fork is unsuc­cessful.

        In your code example you have

        if (my $pid = fork()) { # a true or non-zero value for the parent # stuff } else { # a false value or 0 for the child # stuff }
        Your logic is the same as mine.

        I used system because that is what he was using, it makes it clearer (at least to me) how his example correlated to my solution. I also tend to leave out the extra error checking because it can cause one to miss the point of the example...and by that token, you're not checking to see if your fork failed. :)

        To error test everything I guess the code would look like

        foreach my $wks (@wkslist) { my $pid = fork; if (!defined($pid)) { die "fork failed: $!"; } elsif ($pid == 0) { # child print "rshing to $wks\n"; exec("$rsh_cmd $wks ls") || die "exec failed for $wks: $!"; } else { push(@pids,$pid); } } foreach my $pid (@pids) { waitpid($pid,0); if ($? != 0) { print "non zero exit from $pid: $?"; } }
        give me a bit and I'll figure out how to make $? look pretty :)

        /\/\averick
        perl -l -e "eval pack('h*','072796e6470272f2c5f2c5166756279636b672');"

Re (tilly) 1: Background process using a system call
by tilly (Archbishop) on Aug 21, 2001 at 05:13 UTC