Your parent process needs to wait() for the children to exit.

Have you traced what your program does? Lets give it the arguments @ARGV = ( 3, "echo", "Foo!").

  1. Parent shifts off the count of 3, @ARGV is now ("echo","Foo!"). The for loop is set up so $i takes successive values 1,2,and 3.
  2. When $i is 1, child1 starts sleeping for 30 seconds. Parent immediately loops to:
  3. $i is 2, child2 starts sleeping for 15 seconds. Parent immediately loops to:
  4. $i is 3, child3 starts sleeping for 7 seconds. Parent is done with the loop, so...
  5. Parent runs system('echo', 'Foo!'), and exits. All the kids are still sleeping. System init process inherits the kids.
  6. Child3 runs system('echo', 'Foo!') six or seven seconds later, unless already killed by init.
  7. Child2 runs system('echo', 'Foo!') seven or eight seconds later, unless already killed by init.
  8. Child3 runs system('echo', 'Foo!') fifteen or sixteen seconds later, unless already killed by init.
There is no real problem with that, except that I don't think it's doing what you wanted it to do.

The trouble begins if the parent's instance of system(@ARGV) runs longer than some of the kids do. By not calling wait() for the dead kids, the parent leaves them zombie.

I won't worry here about the lack of error checking, use strict;, or the mishandling of the kids. Instead, I'll ask if this would serve you better:

#!/usr/bin/perl -w use strict; my $count = shift; my $interval = 60 / $count; for (1..$count) { system(@ARGV); select(undef,undef,undef,$interval); }
The select code is an accurate sleep, giving more even timing than the one second granularity of sleep() allows. This will do what you want if the system call is brief.

If you need evenly spaced start times for long running calls, you do need to fork them off. Here's one way to do that:

#!/usr/bin/perl -w use strict; my $count = shift; my $interval = 60 / $count; my ($pid,%kids); for (1..$count) { defined($pid = fork()) or warn $! and last; # can't die, kids to t +end $pid or exec(@ARGV); $kids{$pid}++; select(undef,undef,undef,$interval); } delete $kids{wait()} while %kids;
Using exec() instead of system() lets us avoid handling their return. They will exit on their own. The hash trick for keeping track of children is one of my favorites.

Update: Taint mode would be a very good thing for this program.

Update2 tye is correct, init will kill only if the session ends. A cron job is a session leader (at least on my Vixie cron). petral may well be right, but I took the question to be about running something every 10 seconds or so from a cron job that fires every minute.

After Compline,
Zaxo


In reply to Re: zombies after forking by Zaxo
in thread zombies after forking by very empty

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.