in reply to Process Management

Can you say a little more about what you think you don't get? It's a little hard to know where to begin except to point you at other, more general references...

Do you understand the idea of time-slicing? The idea is that even if you've just got one processor down there running everything, you can handle multiple jobs at the same time by having the processor constantly switching between jobs. In Unix, each of these jobs is called a "process" (or these days, a "thread", which is a similar idea).

In unix-like systems, one process can spin off another process by doing a "fork", which creates a clone of the first process -- and note that both the original and the clone then are running the same code. The code itself has to be able to figure out whether it's the original process (the "parent") or the clone (the "child"), and it can do that by looking at the return from the "fork" command. A "fork" returns the process id of the newly cloned child to the parent... but it doesn't return anything to the child, so the code can check that return value to find out whether it's parent or child.

Just for the hell of it, here's a demo script I wrote recently to show how you can use a child process to handle a long-running task while the parent goes off and does something else. This script has the child reporting on it's status to the parent so that, for example, you can update a "percent done" message while the child is working:

#!/usr/bin/perl =head1 NAME child_to_parent_ipc_demo - child process reports on it's status to the + parent =head1 SYNOPSIS child_to_parent_ipc_demo =head1 DESCRIPTION A demonstration of a technique of spinning off a child process which can report on it's progress back to the parent process, while letting the parent go off and do some other things. =cut use warnings; use strict; # $|=1; our $VERSION = 0.01; use IO::Handle; # brings in autoflush and blocking # first set up a bi-directional pipe, # (will later close one direction) my ($reader, $writer); pipe $reader, $writer; $writer->autoflush(1); # still needed, even with modern perls $reader->blocking(0); # keeps reads from hanging my $pid; if ($pid = fork) { # this is parent code close $writer; print "Parent $$ is hearing from child $pid:\n"; while (1) { my $status = ''; $status = <$reader>; # magic "blocking(0)" keeps # this from blocking if ( defined( $status ) and ( $status =~ m{ ^ \d+ $ }xms ) ){ # recieved an update child process status chomp( $status ); print "\n$status% "; if ( $status >= 90 ) { close $reader; print "\n"; exit; } } else { # can continue doing stuff here while child is running print "."; sleep 1; } } } else { # this is child code die "cannot fork: $!" unless defined $pid; close $reader; # child code that takes awhile, but reports on it's status for my $i (1..10) { # the child takes a varying amount of time my $pause = int( rand(4) + .5 ); sleep $pause; my $status = $i * 10; print $writer "$status\n"; } close $writer; # i/o doesn't go through until closed, # *unless* autoflush is set to 1 exit; } __END__ =head1 SEE ALSO L<perlipc> The Perl Cookbook, 2nd ed. Chapter 16 (interprocess communication) Chapter 7 (non-blocking i/o) =head1 AUTHOR Joseph Brenner, E<lt>doom@kzsu.stanford.eduE<gt> =head1 COPYRIGHT AND LICENSE Copyright (C) 2008 by Joseph Brenner This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.2 or, at your option, any later version of Perl 5 you may have available. =head1 BUGS None reported... yet. =cut

Replies are listed 'Best First'.
Re^2: Process Management
by gwadej (Chaplain) on Jan 18, 2009 at 02:11 UTC

    Although not directly related to the OP's question, this is still important.

    There's a subtle bug in this code that I have seen repeatedly. This code assumes two potential returns from fork. The fork call actually has three potential return values, not two.

    • positive integer - pid of child process returned to the parent process
    • 0 - returned to the child process
    • undef - returned to the parent process if the fork call cailed.

    I learned about this when a long-running process started failing when it was moved to a much, much faster machine. It forked enough child processes in a burst to run out of process slots and then failed. Since the return was not true, it went on to do work as a child and exited when it was done. Now, the main process was gone.

    Update: As almut pointed out, the undef case was dealt with in the else. I can only say that I'm a little oversensitive to this bug after losing a fair amount of time on the above case.
    G. Wade
      There's a subtle bug...

      Isn't doom already taking care of the 'fork() failed' case (returning undef) with this line?

      ... } else { # this is child code die "cannot fork: $!" unless defined $pid; # <-- ...

        Drat! I missed that.

        G. Wade
      That's interesting. So is your point that this is a case where one should check if the return is defined (and not just "true"), or does there need to be a third branch to handle the "0"?

      Neither the examples in perlipc or in the Perl Cookbook make any attempt at special handling of a return of "0".

        My point is that there are actually three cases that need to be dealt with. Since fork almost never fails, people often forget the undef case and just handle true as parent and false as child.

        I like handling them as three separate cases, because the parent may be able to recover.

        In any case where the parent continues, handling the undef is important. Otherwise, you end up with a subtle, hard to reproduce bug.

        G. Wade
Re^2: Process Management
by koolgirl (Hermit) on Jan 19, 2009 at 19:21 UTC

    doom, Thank you very much! That explanation cleared up a lot of questions about the parent - child process concepts I've been struggling with. I know my post was so very generalized, and that bothered me, but I really just don't even know enough about the general concepts of process management, to formulate a well written specific question, so this was the best I could come up with.