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

Hi,
I have a situation as follows: Thanks in advance, any reply deeply appreciated

Edit kudra, 2001-10-09 Removed code tags; added markup

  • Comment on How do you get PID of a program called using system call?

Replies are listed 'Best First'.
Re: How do you get PID of a program called using system call?
by blakem (Monsignor) on Oct 08, 2001 at 12:12 UTC
    Here is an example to get you started:
    #!/usr/bin/perl -wT use strict; %ENV = (); # clean out the %ENV hash to prevent mischief $ENV{PATH} = '/bin'; my @pids; # array for storing childr +ens pids my $cmd = 'sleep 2; echo "I am child $$"'; # command children will ex +ecute for (1..4) { my $childpid = fork() or exec($cmd); # fork off a child push(@pids,$childpid); # store the childs pid in @pid +s } print "My Children: ", join(' ',@pids), "\n"; waitpid($_,0) for @pids; # wait for children to finish print "Children are done\n";

    -Blake

      You should really check the return values from fork() and exec() or you can get yourself into a lot of mess.

      If fork() was not able to fork, it will return undef and if exec() is not able to run the program it will return.

      my $pid = fork(); if ($pid) { push @pids, $pid; } elsif (defined $pid) { exec($cmd); die "Cannot exec '$cmd': $!\n"; } else { die "Cannot fork: $!\n" }
      Not catching the exec is potentially the most dangerous as the child process then continues in the loop, just the same as the parent. In this cas you would end up filling the process table.
        Good point. I certainly should have checked the return values. There is a large potential bug lying in wait there.

        I don't think this would ever fill up the proc table though, The loop is bound by a for (1..4) which means that in the wost case, we would have:

        1 parent through the first time (creates 1 child) 1 parent 1 child the second time (creates 2 children) 2 parents 2 children the third time (creates 4 children) 4 parents 4 children the fourth time (creates 8 children)
        So at most I see a possible 16 procs being active at once.... of course they might never exit due to the messed up @pids array, but thats another matter.

        Again, thanks for the catch.

        -Blake

Re: How do you get PID of a program called using system call?
by virtualsue (Vicar) on Oct 08, 2001 at 12:39 UTC
    To clarify, a bit, system does do a fork and exec to run the program you specify, but it also waits for that program to complete before returning control back to your code. This means that you cannot use system() to (directly) get 4 processes running at the same time, and that you cannot try to keep track of let alone control the processes created by system(), because these processes are gone by the time your program starts running again.

    You already have a reply from blakem which provides a piece of code demonstrating the use of fork & exec. If you'd like more info, doing a Super Search for nodes containing 'fork' and 'exec' in the text comes up with a lot of useful looking hits.

Re: How do you get PID of a program called using system call?
by dws (Chancellor) on Oct 08, 2001 at 11:56 UTC
    Invoking system() 4 times in a row won't give you 4 simultaneous processes unless whatever you're invoking does a fork(). Even then, you won't easily be able to get a pid unless somebody is kind enough to save it for you.

    Your best bet might be to roll the fork()/exec() yourself, so that the parent process can get the child pid directly from fork().

fork and wait example (the second)
by C-Keen (Monk) on Oct 08, 2001 at 20:41 UTC
    Hi! I would just like to redirect you to this node where I have already answered to this question. There is also sample code to get you started :-)

    Hope this helps,
    C-Keen

Re: How do you get PID of a program called using system call?
by monk_e_magic (Novice) on Oct 09, 2001 at 03:45 UTC
    Thank you all for your reply, I found it very helpful. However, when I mention about having 4 system calls that resulted in 4 pids, I mean the following(having them runnning in background):
    my $cmd = "process_file -c arg1 -d arg2"; for(1..40) { if(!WINDOWS) { system("$cmd > /dev/null &"); } else { system("sh -c \"$cmd > /tmp/null \"&"); } }
    as you can see, the above code will gives me 4 processes running in the back ground, but I have no control over those pids
      With this approach in mind, your best solution would be to iteration through the process table following execution of your system processes. Under *NIX, you would want to use Proc::ProcessTable (which I have written about before here). For Windows, you should take a look at either Win32::Process or Win32::ProcFarm.

      Even so, I still think that you would find the best solution from pre-forking within your script, rather than launching system processes and detaching yourself from the controlling tty. This pre-forking approach would give you greater control, without the need to extraneous loops and control structures, of your spawned processes.

       

      Ooohhh, Rob no beer function well without!