Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Infinite Loop Question

by joeymac (Acolyte)
on Nov 08, 2011 at 18:48 UTC ( [id://936851]=perlquestion: print w/replies, xml ) Need Help??

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

I am writing a script that I want to infinite loop. I have read over node 37048, and I have a question that is not answered there. I want it to truly be an infinite loop (i.e. I would like it to run indefinitely not just a really long time). Currently I am using a

 for (;;){...}

loop. The script runs for about 24 hours then terminates itself unexpectedly. The code does not have any "..or die" statements in the interest of not dying from the infinite loop once it is started. Does anyone know if Perl has some syntactic sugar that "invisibly" counts iterations even though a limit is not declared? Could this cause it to eventually die on a integer stack overflow? I thought this may be a possible cause of the code dying. If this is true, is it then a better option to use a while true loop? Thanks for any input and/or advice!

Replies are listed 'Best First'.
Re: Infinite Loop Question
by roboticus (Chancellor) on Nov 08, 2011 at 18:56 UTC

    joeymac:

    The only things I can think of are:

    • There may be an alarm set elsewhere in the code.
    • There may be resource limits on the user account that's shutting the job down.
    • There may be a connection timeout (firewall or some such) that's closing the connection and shutting the job down.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Thanks for the quick response! There are no alarms coded in the script. Your second suggestion is something that I am not sure about. I will look into this. The third suggestion I believe I accounted for with a second nested infinite loop that tries to reconnect (using Net::FTP) until connection is reestablished. It then exits this loop with a last statement and returns to the overall infinite loop.

      for(;;) {... my $host = something; my $ftp = Net::FTP->new($host, Timeout => 30); if (defined($ftp)) { my $TODAY = time; print LOG "Established ftp connection with $host\n"; print LOG "at: ", scalar(localtime($TODAY)), "\n"; } else { for (;;) { print LOG "Unable to make connection with $host\n"; print LOG "Try to reconnect in 5 secs to $host\n"; sleep 5; my $ftp = Net::FTP->new($host, Timeout => 60); if (defined($ftp)) { my $TODAY = time; print LOG "Established ftp with $host\n"; print LOG "at: ", scalar(localtime($TODAY)), "\n"; last; } } } ...}

        What is the last message that's printed to LOG?

        That might help in finding the call that's causing the script to exit.

Re: Infinite Loop Question
by mrstlee (Beadle) on Nov 08, 2011 at 20:30 UTC
    for (;;;)
    will work, though as rthhawk says
    while(1)
    is maybe a little more conventional.There's no inbuilt limit to the loop either way.
    As to why it ends:
  • Some other process/es on the host chews up the cpu?
  • Some other process/es on the host gorges the memory?
  • Your LOG target gets zapped by some other agent?
  • Other?

  • Hard to say.

    Options?

    You could set up the script to run under some process monitor or other. There are quite a few around. For a bit of fun you could write your own (but who monitors the monitor?).

    If you wrap the whole thing in an eval you maybe able to trap the condition that causes the exit and resume the loop.

    See eval documentation.

      What I did was write a quick script to send STDERR to a log file. Things went astray again and this is the message that I got.

       fileparse(): need a valid pathname at ftpData.pl line 312

      I am using fileparse (File::Basename) to disregard any file extensions in directory comparisons and to remove the existing extension when the file is copied and renamed with a different extension, like so:

      #Disregard file extension in comparison: foreach my $item (@wrkDirList) { my ( $fileName, $filePath, $fileExt ) = fileparse($item, qr/\.[^.]*/); $item = $fileName; }

      and

      foreach $item (@filesToRetrv) { my ( $fileName, $filePath, $fileExt ) = fileparse($item, qr/\.[^.] +*/); if (rename($item, $fileName)) { push (@filesToMove, $fileName); } else { print LOG "Rename failed for $localName to $fileName\n"; } }

      So, and correct me if I am wrong, somewhere along the line it looks like fileparse is getting passed an empty filehandle? I'm not really sure how this could happen. The STDERR message seems to be occurring at the second instance of fileparse (the one working on @filesToRetrv). Here is a little snippet with info about this array and what goes into it:

      foreach $fileToGet (@matches) { my $remoteFileSize = $ftp->size($fileToGet); $localFileName = "$fileToGet".".xxx"; $ftpReturnVar = $ftp->get($fileToGet, $localFileName); $localFileSize = (stat "$workingDir/$localFileName")[7]; if ($remoteFileSize == $localFileSize) { push (@filesToRetrv, $ftpReturnVar); } else { ... } }

      Any ideas? Thanks for the help!

        One thing lest the PBP fundamentalists get you - always use a lexical variable in foreach loops:
        foreach my $fileToGet (@matches) { ...
        What happens if $ftp->get fails? You may want to check whether you get a valid return value e.g.
        $ftpReturnVar = $ftp->get($fileToGet, $localFileName); defined $ftpReturnVar or next;
Re: Infinite Loop Question
by ikegami (Patriarch) on Nov 08, 2011 at 19:14 UTC

    for ( ... ; ... ; ... ) is not a counting loop. It never creates a counter. It's really a while loop in disguise (in terms of function).

    What's the process's exit code? It will tell you which signal killed the process if it was a signal (e.g. SIGSEGV, SIGCHLD, SIGPIPE), and the exit code will likely be an errno if the process didn't die from a signal. (perl -E'say $!=123;' to find out what errno 123 means.)

Re: Infinite Loop Question
by rthawkcom (Novice) on Nov 08, 2011 at 19:46 UTC
    I might be missing something here, but why are we not using the traditional:
    while(1){... do stuff...}
    This is what I use when I write deamons. Maybe it is bailing out due to lack of available memory?
      while (1) and for (;;) (which is also quite traditional) result in the same code.
      $ perl -MO=Concise,-exec -e'for (;;) { f() }' 1 <0> enter 2 <;> nextstate(main 3 -e:1) v:{ 3 <{> enterloop(next->8 last->9 redo->4) v 4 <;> nextstate(main 1 -e:1) v 5 <0> pushmark s 6 <#> gv[*f] s/EARLYCV 7 <1> entersub[t3] vKS/TARG,1 8 <0> unstack v -e syntax OK $ perl -MO=Concise,-exec -e'while (1) { f() }' 1 <0> enter 2 <;> nextstate(main 3 -e:1) v:{ 3 <{> enterloop(next->8 last->9 redo->4) v 4 <;> nextstate(main 1 -e:1) v 5 <0> pushmark s 6 <#> gv[*f] s/EARLYCV 7 <1> entersub[t3] vKS/TARG,1 8 <0> unstack v -e syntax OK $ diff -u \ <( perl -MO=Concise,-exec -e'while (1) { f() }' 2>&1 ) \ <( perl -MO=Concise,-exec -e'for (;;) { f() }' 2>&1 ) \ && echo same same

      No particular reason why I used

       for(;;) {...}

      instead of

       while(1) {...}

      It is my understanding that the two are pretty much interchangable.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://936851]
Approved by kennethk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2024-04-26 03:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found