Reputation: 6994
So I am trying to create a Perl program that forks a worker and waits for it to finish. In my real use case I need to fork many workers and wait for them all, so I thought I would try a test case with a single worker. My concern here is that when I run this program in the terminal, sending a ^C
doesn't kill the parent, even though the signal handler seems like it should reap the child process and cause the parent to exit normally. I am trying to use waitpid
to keep the parent alive so that it can receive signals and pass them along to the child, but the parent process seems to ignore ^C
entirely.
use strict;
use warnings FATAL => 'all';
use POSIX ":sys_wait_h";
my $cpid;
sub reap_children_and_exit {
defined $cpid and kill 'HUP', $cpid;
exit 0;
}
$SIG{INT} = \&reap_children_and_exit;
my $child_text = <<'EOF';
perl -e 'while (1) { printf "%s\n", rand() }'
EOF
$cpid = fork;
if ($cpid == 0) {
exec($child_text)
}
waitpid($cpid, WNOHANG);
Upvotes: 1
Views: 851
Reputation: 294
If you don't need to implement all by yourself and can use a module, I would recommend: https://metacpan.org/pod/Parallel::Prefork This module wraps all the worker/children creation and management for you easily, besides, it saves memory usage.
If you plan to create a daemon, there is another one, that can manage forks: https://metacpan.org/pod/Daemon::Control
Or try this solution:
use strict;
use warnings FATAL => 'all';
use feature 'say';
use POSIX ":sys_wait_h";
BEGIN {
sub reap_children_and_exit {
my $signame = shift;
my $pid = shift;
defined $pid and kill $signame, $pid;
say "$pid => Received '$signame' !";
exit 0;
}
$SIG{INT} = \&reap_children_and_exit;
}
my %children;
$SIG{CHLD} = sub {
# don't change $! and $? outside handler
local ($!, $?);
while ( (my $pid = waitpid(-1, WNOHANG)) > 0 ) {
delete $children{$pid};
reap_children_and_exit('HUP', $pid);
}
};
my $child_text = <<'EOF';
perl -e 'while (1) { printf "%s\n", rand(); sleep 1; }'
EOF
while (1) {
my $pid = fork();
die "Cannot fork" unless defined $pid;
say "I'm the PID $pid";
if ($pid == 0) {
say q{I'm the parent};
exit 0;
} else {
$children{$pid} = 1;
system($child_text);
}
}
I wish this helps you. Best regards!
Upvotes: 1
Reputation: 386501
I am trying to use waitpid to keep the parent alive
You told waitpid
to return immediately. Change WNOHANG
to 0
.
Upvotes: 3