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

Hi, I have a program that while the parent process is doing something, child process counts up the run time and displays it. Simplified code woll be something like,
if($pid=fork){ while($c = ReadKey){ doing something... ; } } else { my $count = 0; while(1){ sleep(1); print $count++; } }
Now the problem is when parent process is done or exited, how can I let child process know so that it can exit as well ? And in the first place, I'm not even sure if this is a good way to count the time in parallel with other tasks. In the above code, the first while loop is stopped until some key is typed in, so that I cannot count the run time in that loop, and the best I came up with is having a child process counting the time and displaying it separate from main(parent) process. If there are any better ways, I'd appreciate your suggestion.

Replies are listed 'Best First'.
Re: Parent process finished. How to exit the child process.
by spazm (Monk) on May 07, 2010 at 04:29 UTC
    Some options:
    1. parent sends kill signal to child when parent processing is complete. Child dies. parent reaps child and exits (or continues, I suppose).
    2. reverse the roll of parent and child. The child does the computing and the parent handles the counting&display. Child exits when complete and parent reaps child via SIG CHLD handler.
    if(my $pid=fork){ while(my $c = ReadKey){ #doing something... ; } kill( HUP => $pid ); wait(0); } else { my $count = 0; while(1){ sleep(1); print $count++; } }
    if(my $pid=fork){ #parent my $run = 1; $SIG{CHLD} = sub { $deadchildpid = wait; $run = 0 }; my $count = 0; while($run){ sleep(1); print $count++; } } else { #child while(my $c = ReadKey){ #doing something... ; } }
Re: Parent process finished. How to exit the child process.
by BrowserUk (Patriarch) on May 07, 2010 at 04:49 UTC

    Just use ReadKey in timed mode:

    #! perl -slw use strict; use Term::ReadKey; ReadMode 4; my( $count, $c ); until( defined( $c = ReadKey( 1 ) ) ) { print ++$count; } ReadMode 0;

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Parent process finished. How to exit the child process.
by Marshall (Canon) on May 07, 2010 at 10:19 UTC
    You asked: If there are any better ways, I'd appreciate your suggestion.

    What you are describing is a scenario where something is doing "work" and a completely separate thing is marking off time for the user. A big problem with this approach, is that what the user is looking at, has no connection with any actual "progress of work". If the "work" grinds to halt due to some extended retry sequence or some program fault, the user is oblivious to this. He just sees some clock continuing to count. This can be especially problematic if your program can run for a "very long time". What's a long time is of course very application dependent.

    One of the bad things that can happen is that the user kills the program after awhile even though everything is going just fine. The other problem that can happen is that it takes the user an inordinately long time to come to the conclusion that the program is "hung" and this wastes a lot of time. Both of these scenarios are bad!

    I believe that a MUCH better approach is to present the user with some measurement of actual "work progress".

    If it is possible, some "percent completed" measurement is great! If not possible, then some measurement like: number of files, number of records, number of directories, etc processed is very good.

    Basically there are 2 main objectives: 1) present the user with some on-going status in a "timely" manner. I would suggest something less than every 20 seconds although in some applications say every second is appropriate. 2) This status should have some direct connection to the "work progress".

    One of the ways that this is done is to call some subroutine, say: update_status(...) at some major work completion part of your main loop. This sub decides whether to update the user's display or not. You will find that updating a GUI or even writing to the command line is relatively "expensive" and you don't want to do it "too often".

    So instead of having some essentially separate thing displaying "elapsed time", you call update_status(...) periodically within your main program at appropriate progress points. This sub has a "time throttle" on it so that it doesn't "go crazy updating info". For example getting current system epoch time is very performant and this sub can just compare current time with last update and decide that it hasn't been a second yet since last user update and it does nothing.

    You don't want to call update_status() so often that there is any significant amount of processing power being used, but you want to call it often enough that the user display is getting updated in a "timely manner". Typically this routine is so performant that calling it 100x or even 1,000x per second or even more often makes no difference at all in your app's performance (<0.1%).

    I believe that such an approach is FAR superior to some sort of separate timer process.

Re: Parent process finished. How to exit the child process.
by rovf (Priest) on May 07, 2010 at 07:27 UTC
    And in the first place, I'm not even sure if this is a good way to count the time in parallel with other tasks.
    I don't see either what purpose it has to "count a time". We don't measure a time by "counting" (and don't forget that a sleep(1) only means that the process sleeps for at least 1 second, not that it sleeps for exactly one second), and I also don't see what advantage it has to do this time measurement in a separate process instead in the parent process, but if you insist doing so: In addition to the other suggestions you already got, there are many other ways to set up a communication between parent and child, for example named pipe, shared files or shared memory.

    But maybe you should tell us why you want to measure process times. Do you want to time out a possibly hanging process? This may be done better in a completely different way.

    -- 
    Ronald Fischer <ynnor@mm.st>

      OK, let me explain what I'm trying to do. Being bored, I started writing a old computer game called sokoban today. The simple example looks like this and it runs on Xterm.

      XXXXXXXXXXXXXXXXXX XX XXXXXXXXXXXXX XX XXXXXXXXXXX XX @ XXXXXXXXXXXX XX@XXXXXXXXXXX sX X XXXXXXXXXXX sX X * X XXXXXXXXXXXXXX XX XXXXXXXXXXXXXXXXXX

      * is a "player" which you manipulete its move by h/k/l/j key and the "player" pushes '@'s through the open space(where no 'X's are)to move them to the locatins marked as 's'. I want to measure the time and display it while the game is going on.

      The below is the initial code. $c could be h/k/l/j to move the player('*') to left/up/right/down(vi's key-bind) and whenever these keys are typed, the player gets moved accordingly. Initially, I did it with non-blocking read like this.

      while(1){ if($c = Readkey(-1)){ # running/playing game etc. } sleep(1); print $count++; }

      however, the time lag caused by sleep command was annoying especially when typing in continuously. The next I did was making sleep time very short, but after a while, CPU fan of my laptop started running and got noisy. At this point, I thought using sleep and ReadKey(-1) in the same loop didn't work well.

      So I was wondering how I could put the sleep command and ReadKey to the separate while loops, then I came up with the idea to separate the process for game handling and time measurement. By separating the tasks, time measurement and game handling work independently, and I don't have to use nonblocking read(because halting the looping by blocking read doesn't hurt anything anymore) so that the loop gets active only when keys are pressed which helps my laptop keep cooler.

      At this moment, I modified the program based on the 2nd option suggested by spazm and it's working, but if there are any better ways (or right ways), I'd like to know. As you can see, this is not something to handle the system tasks and the measured time is not necessarily very accurate.

        I want to measure the time and display it while the game is going on.
        So you want to display kind of "running stopwatch", updated every second?

        Since sleep(1) is unreliable, you can't use counting. Instead I suggest you use the following approach: You use a high-resolution timer (for example, Time::HiRes), sleep for around 0.1 or 0.2 seconds (of course, the *actual* sleep time will differ from this too a bit), and instead of counting, use time and simply display the actual time.

        The only purpose of using the hires timer instead of the normal sleep is to make the update of the display more smoothly.
        -- 
        Ronald Fischer <ynnor@mm.st>
Re: Parent process finished. How to exit the child process.
by johngg (Canon) on May 07, 2010 at 11:03 UTC

    You may be able to get what you want using the tv_interval() method in Time::HiRes.

    Cheers,

    JohnGG