Perl 后台进程

4

我将尝试在perl中运行一个后台进程。我创建了一个子进程,用于调用另一个perl脚本。我想要和这个子进程并行地运行几行代码。当子进程完成后,我想要打印一行代码。

主脚本

#!/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);

期望输出

子进程之前
等待命令之前
(应该等待20秒然后打印)
等待20秒后

1
那么你看到了什么?值得注意的是,在system调用之后的所有内容都将由父进程和子进程执行。 - Mark Reed
你说得对,它打印了两次。我该如何控制它? - dreamer
dreamer: 这是因为在Perl中0是一个*defined*值。 - Alan Haggai Alavi
已经修复了您在编辑中添加的错误。 - ikegami
@AlanHaggaiAlavi 即使修复了这个问题,由于 if 分支没有包含 exit,所以在父进程和子进程中都会执行其后的代码。 - Mark Reed
3个回答

8

您的脚本存在许多问题。一直:

use strict;
use warnings;

局部化特殊变量是一个好的实践。只有包含特殊值undef的变量才会对defined返回false。因此,其他所有值(即使是0;在这种情况下)都会对defined返回true。在另一个脚本中,shebang写法不正确。

#!/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";

7

perlipc文档中的“后台进程”部分如下:

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.

在您的程序中,将一个“&”符号添加到对system的参数中可以极大地简化您的主程序。
#! /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";

我不小心错过了那部分,但我已经在代码中包含了它。 - dreamer
1
@dreamer,Greg Bacon建议使用fork的替代方案。 - ikegami

1

fork的返回值处理有点棘手。 Aristotle最近的文章介绍了一种简洁明了的分叉惯用语,对于你的情况,看起来是这样的:

#!/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';
    }
}

请注意 exec $^X => '...' 这一行代码:变量$^X保存了当前Perl可执行文件的完整路径,因此可以保证使用“正确的Perl版本”。此外,在预先fork时,system调用是无意义的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接