tags:

views:

210

answers:

2

Hello friends,

How can I make a live time counter that ticks on the screen in parallel to part of a working program?

let's say I have the following little sub code which run an internal program for a couple of minutes:

system (`compile command`);
exec "simu -sh";

While waiting it to end, can I open a fork or something that output to stdout a running clock time?

Another question may be, how can I output to screen the ALARM counter without hurt the rest of the script?

+3  A: 

It is important to give context to your question. You already have two processes: a parent and a child. The child is replacing itself with the exec, so you can't use the child to do any form of monitoring, but the parent is available. We just need to make the waitpid call non-blocking (i.e. it won't wait to be successful, it will fail right away). This also gets rid of the need for the eval and alarm functions:

#!/usr/bin/perl

use strict;
use warnings;
use POSIX ":sys_wait_h";

my $timeout = 180;
my $program = "simulator --shell";

die "could not fork: $!" unless defined (my $pid = fork);

#this is the child process
unless ($pid) {
    exec $program;
    #if we reach this code the exec failed
    die "exec of simulator failed: $!";
}

#this is the parent process
my $tries = 0;
#check to see if $pid is done, but don't block if it isn't
until (waitpid(-1, WNOHANG) == $pid) {
    #put what you want to print while waiting here:
    print scalar localtime, "\n";

    if ($tries++ > $timeout) {
        warn "timed out, sending SIGKILL to simulator\n";
        kill 9, $pid;
        waitpid($pid, 0);
        last;
    }
} continue {
    sleep 1;
}
Chas. Owens
I don't have a choice or don't know about a way to avoid the exec function. When I run it - the time counter can't stop, maybe because the exec function run inside the work place. Still Is there any side way to conduct the clock counter while exec command run inside it ? Or can I output the ALARM counter(belong to the exec command kill pid) to screen ?
YoDar
Why not just use system() instead of exec()?
Chas. Owens
I used the exec() as Mani suggested in the following link:http://stackoverflow.com/questions/1165316/how-can-i-limit-the-time-spent-in-a-specific-section-of-a-perl-scriptIf there is another way to use the timeout window without getting a dead coming problem I would gladly happy to know :)
YoDar
A: 

How about spawning it as a thread and then waiting for a value to be set (assuming you have a thread enabled perl):

# Modules to be used
use strict;
use warnings;
# Threads module
use Thread;

# Share out the variable so it can be set and 
# view by main thread and spawned thread
my $value:shared = 0;  # value to be set when completed

# Create a thread with a subroutine to compile and set the passed in reference
# to 1 when complete.  Pass in the reference to value
my $t = Thread->new(sub {`compile command`; ${$_[0]} = 1;}, \$value);

# Counter to count
my $count = 0;

# Loop until the routine set the value
while ( $value == 0 ) 
{
   # Increment the count and print it out.  
   $count++;
   print "$count\n";
   # Sleep for second to let the other thread process
   sleep 1;
}
# Thread as completed so join back together
$t->join();

# Indicate items have completed.
print "Done $count\n";

I ran the example above in ActiveState PERL 5.10 on Windows XP.

This will give some indication in seconds of how long it took to do the command. Hopefully you are not looking for more then a second of granularity. You could substitute localtime() for the counter if you wanted the actual time.

I am not locking the reference as I am only concerned when it is set, which is at the end of the routine, to it will complete and join back up.

For more information on perl threads.

Or look at Perlmonks.

Glenn