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

Hi

I'm having a problem with the code below because the pid returned is not a running process. The script I'm calling process_tar.pl simply echos the filename and does a sleep 40, but its pid differs to the one returned below.

$cmd="$scriptsdir/process_tar.pl $file >> /tmp/testlog &"; + $pid=open(PID,"|$cmd"); if(pidrunning($pid){ print "PID $pid is running"; }else{ print "PID $pid is not running"; } # check if process is running sub pidrunning{ ($pid)=@_; $exists = kill 0, $pid; return $exists; }

I wondered if it going wrong because of the ampersand at the end of the command? If I don't use the ampersand, the parent script waits until the command has completed which defeats the purpose of forking it. I have a feeling there might be a better way to do this, so if anyone can see what I'm doing wrong I'd appreciate any help.

Thanks,

js1'

Replies are listed 'Best First'.
Re: wrong pid
by shmem (Chancellor) on Apr 23, 2007 at 13:47 UTC
    With that code
    $cmd="$scriptsdir/process_tar.pl $file >> /tmp/testlog &"; + + $pid=open(PID,"|$cmd");

    you are opening a pipe to a shell which then runs perl. The shell and the perl process don't have the same PID:

    #!/usr/bin/perl # file pid.pl sleep 1; print "$0 PID: $$\n";
    #!/usr/bin/perl my $cmd = 'echo my PID is $$ && ./pid.pl'; my $pid = open PID, "| $cmd" or die "Can't run ./pid.pl: $!\n"; print "PID returned by open: $pid\n"; sleep 2; __END__ my PID is 4465 PID returned by open: 4465 ./pid.pl PID : 4466

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Thanks. That makes sense. What's the correct way to do this then? How do I get the perl program's pid instead of the shell?
Re: wrong pid
by kyle (Abbot) on Apr 23, 2007 at 13:53 UTC

    My guess is that the PID you're getting back is the PID of the shell before it forks process_tar.pl. So yes, I think the ampersand is your problem.

    If I don't use the ampersand, the parent script waits until the command has completed which defeats the purpose of forking it.

    It looks as if you want to send input to the subprocess. Do you want to do that and then not have to wait for it to finish? I suggest you fork first, and run the command after.

    my $child_pid = fork(); if ( $child_pid ) { # parent goes about its business } elsif ( defined $child_pid ) { # child my $pid = open(PID, "|$cmd") or die "Can't fork: $!"; # blah blah # this hangs until process_tar.pl finishes. close(PID) or die "Can't close: $!"; exit; } else { die "Can't fork: $!"; }

      Thanks. You're right. I want to send the filename to the subprocess process_tar.pl.

      #!/usr/bin/perl print "\n" . $ARGV[0]; sleep 40;

      Then after launching this, I want the parent script to carry on running and launch 5 more process_tar.pl's, then wait until one or more of these have finished before running any more.

      So you're saying use fork for this?

        Yes, I was saying use fork for this. Given that you want to launch several processes and wait for them before running more, I might suggest Parallel::ForkManager instead.

Re: wrong pid
by MonkE (Hermit) on Apr 23, 2007 at 13:54 UTC

    The open method is invoking your Perl script via a shell and that shell's PID is what you get back from the open() call. When you include the ampersand at the end, the invoking shell terminates as soon as it backgrounds process_tar.pl, and so in the course of a few milliseconds at most, the PID you get back from open is no longer running.

    Also, if you are interested in the output from process_tar.pl, then you need your open invocation to look like this:

    $pid = open(PID,"$cmd &|") or die $!; # further on you can read back the output of the command with ... while ( <PID> ) { echo "PID output: $_\n"; }
    The way you had it, process_tar.pl was expecting input to be piped to it.
Re: wrong pid
by shigetsu (Hermit) on Apr 23, 2007 at 13:14 UTC

    As a side note, I recommend using strictures:

    use strict; use warnings;

    Doing the PID 'munging' yourself just seems wrong. A few modules that look appealing:

    There are more related modules on CPAN.

      Hackish indeed! Maybe, but I didn't really want to use a sledgehammer to crack a nut, and I want the script to be as quick as possible.

      Also I'd like to understand what was going wrong in my original code. I might cave in to the Unix::PID module now, although it does has a few prereqs:

      Warning: prerequisite Class::Std 0 not found. Warning: prerequisite Class::Std::Utils 0 not found. Warning: prerequisite List::Cycle 0 not found. Warning: prerequisite Math::Fibonacci::Phi 0 not found. Warning: prerequisite Time::HiRes 0 not found. Warning: prerequisite version 0 not found.