Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reaping child processes from Perl

I have a script that spawns a set of children. The parent must wait for each of the children to finish.

My script performs similar to the following perl script:

#! /usr/bin/perl
use strict;
use warnings;

print "I am the only process.\n";

my @children_pids;

for my $count (1..10){
        my $child_pid = fork();
        if ($child_pid) {  # If I have a child PID, then I must be the parent
                push @children_pids, $child_pid;
        }
        else { # I am the child
                my $wait_time = int(rand(30));
                sleep $wait_time;
                my $localtime = localtime;
                print "Child: Some child exited at $localtime\n";
                exit 0; # Exit the child
        }
}

foreach my $child (@children_pids) {
        print "Parent: Waiting on $child\n";
        waitpid($child, 0); 
        my $localtime = localtime;
        print "Parent: Child $child was reaped - $localtime.\n";
}

print "All done.\n";

Similar to the code I've provided above, each child may take a different time to finish.

The problem is when I try to reap the children by looping over the children PIDs, in that last foreach block, the parent waits for the children in the order that they are created.

Obviously the children do not finish in the order which they are spawned and so I'm left with a bunch of zombie processes for children that happen to finish early.

In my actual code, these children may finish days before one another and the number of zombie processes floating around can grow in the hundreds.

Is there a better way for me to reap a set of children?

like image 647
EMiller Avatar asked Jun 06 '12 23:06

EMiller


People also ask

How do I fork in Perl?

The fork() Function in PerlThe fork() function is used to clone a current process. This call create a new process running the same program at the same point. It returns the child pid to the parent process, 0 to the child process, or under if the fork is unsuccessful.

Can I fork in child process?

Fork system call is used for creating a new process, which is called child process, which runs concurrently with the process that makes the fork() call (parent process). After a new child process is created, both processes will execute the next instruction following the fork() system call.

How do you find the PID of all child processes?

Using the /proc File System It contains information about the kernel, system, and processes. We can find the PIDs of the child processes of a parent process in the children files located in the /proc/[pid]/task/[tid] directories.

Can processes create children?

The process that used the fork() system call is the parent process. In other words, a parent process is one that creates a child process. A parent process may have multiple child processes but a child process only one parent process.


2 Answers

If your parent process doesn't need to be aware of its children's completion status then you can just set

$SIG{CHLD} = 'IGNORE';

which will automatically reap all children as they complete.

If you do need to be informed of the children completing, then the signal handler needs to be set to reap all possible processes

use POSIX ();

$SIG{CHLD} = sub {
  while () {
    my $child = waitpid -1, POSIX::WNOHANG;
    last if $child <= 0;
    my $localtime = localtime;
    print "Parent: Child $child was reaped - $localtime.\n";
  }
};
like image 91
Borodin Avatar answered Sep 22 '22 05:09

Borodin


use "-1" for the pid, or use the wait() function so that you wait for any child process. The reaped pid is returned, so you can check it against your list if necessary. If that is unacceptable, then periodically waitpid for each pid in your list with POSIX::WNOHANG() as the second argument.

like image 33
runrig Avatar answered Sep 21 '22 05:09

runrig