perl background process

2019-05-05 18:46发布

问题:

I am trying to run a background process in perl. I create a child process, which is used to call another perl script. I want to run few lines of code parallely with this child process. And after the child process is done.I want to print a line of code.

Main script

#!/usr/bin/perl

$|=1;

print "before the child process\n";

my $pid = fork();

if (defined $pid)
{
    system("perl testing.pl");
}

print "before wait command\n";

wait();

print "after 20 secs of waiting\n";

testing.pl

#!/usr/bin/perl

print "inside testing\n";

sleep(20);

Expected output

before the child process
before wait command
(should wait for 20 secs and then print)
after 20 secs of waiting

回答1:

There are many problems with your script. Always:

use strict;
use warnings;

localising special variables is a good practice. Only a variable containing the special value undef returns false for defined. So, every other value (even a 0; which is the case here) returns true for defined. In the other script, the shebang is wrong.

#!/usr/bin/perl

use strict;
use warnings;

local $| = 1;

print "Before the child process\n";

unless (fork) {
    system("perl testing.pl");
    exit;
}

print "Before wait command\n";
wait;
print "After 20 secs of waiting\n";


回答2:

The “Background Processes” section of the perlipc documentation reads

You can run a command in the background with:

system("cmd &");

The command’s STDOUT and STDERR (and possibly STDIN, depending on your shell) will be the same as the parent’s. You won't need to catch SIGCHLD because of the double-fork taking place; see below for details.

Adding an ampersand to the argument to system in your program can vastly simplify your main program.

#! /usr/bin/env perl

print "before the child process\n";

system("perl testing.pl &") == 0
  or die "$0: perl exited " . ($? >> 8);

print "before wait command\n";

wait;
die "$0: wait: $!" if $? == -1;

print "after 20 secs of waiting\n";


回答3:

fork return value handling is a bit tricky, indeed. Recent article by Aristotle features a nice and concise forking idiom, which, in your case, looks like:

#!/usr/bin/env perl
use 5.010000;
use strict;
use warnings qw(all);

say 'before the child process';
given (fork) {
    when (undef) { die "couldn't fork: $!" }
    when (0) {
        exec $^X => 'testing.pl';
    } default {
        my $pid = $_;
        say 'before wait command';
        waitpid $pid, 0;
        say 'after 20 secs of waiting';
    }
}

Pay attention to exec $^X => '...' line: the $^X variable holds the full path to the current Perl executable, so the "right Perl version" will be guaranteed. Also, system call is pointless when you're pre-forking.