了解Perl fork的工作方式

时间:2019-01-15 01:44:24

标签: perl fork

分叉进程的正确方法是:每个进程运行一个不同的子例程sub1,sub2,...,subN。在阅读了很多以前的主题和材料之后,我觉得我理解逻辑,但是对如何以最简洁的方式编写代码感到有些困惑(可读性对我很重要)。

考虑4个潜艇。他们每个人都有不同的论点。感觉最有效的方法是创建7个fork,每个fork将运行一个不同的sub。该代码将如下所示:

my $forks = 0;
foreach my $i (1..4) {
    if ($i == 1) {
        my $pid = fork();
        if ($pid == 0) {
            $forks++;
            run1();
            exit;
        }
    } elsif ($i == 2) {
        my $pid = fork();
        if ($pid == 0) {
            $forks++;
            run1();
            exit;
        }
    } elsif ($i == 3) {
        my $pid = fork();
        if ($pid == 0) {
            $forks++;
            run1();
            exit;
        }
    } elsif ($i == 4) {
        my $pid = fork();
        if ($pid == 0) {
            $forks++;
            run1();
            exit;
        }
    }

}

for (1 .. $forks) {
    my $pid = wait();
    print "Parent saw $pid exiting\n";
}
print "done\n";

一些要点:

  • 这仅在所有分叉都成功时才有效。但是即使分叉失败,我还是要运行subs(即使它不会并行。在这种情况下,我想我们需要将ifs的subs取出,并且仅在$ pid不是{{ 1}}。类似:

    0

    但是仍然感觉不对。

  • 使用my $pid = fork(); run1(); $forks++ if ($pid == 0); exit if ($pid == 0); 是杀死子进程的正确方法吗?如果进程被exit杀死,我是否仍应使用exit?可以防止僵尸吗?

  • 也许是最有趣的问题:如果我们有15个函数调用,该怎么办?我想以某种方式创建15个fork,但无法创建15个if-else语句-这样就无法读取代码。起初,我认为可以将这些函数调用(以某种方式)插入数组并在该数组上循环。但是经过一番研究,我没有找到可行的方法。

  • 如果可能的话,我宁愿不使用任何其他模块,例如wait

是否有一种干净简单的方法来解决它?

1 个答案:

答案 0 :(得分:5)

这里有几个问题需要解决。

一个基本示例

use warnings;
use strict;
use feature 'say';

my @coderefs;    
for my $i (1..4) { 
    push @coderefs, sub { 
        my @args = @_; 
        say "Sub #$i with args: @args";
    };
}

my @procs;
for my $i (0..$#coderefs) {
    my $pid = fork  // do {
        warn "Can't fork: $!";
        # retry, or record which subs failed so to run later
        next;
    };  
    if ($pid==0) { 
        $coderefs[$i]->("In $$: $i");
        exit;
    }   
    push @procs, $pid;
    #sleep 1;
}    
say "Started: @procs";

for (@procs) {
    my $goner = wait;
    say "$goner exited with $?";
}

我们生成匿名子例程,并将这些代码引用存储在数组中,然后遍历该数组并启动许多进程,并在每个进程中运行一个子进程。之后,所有这些父项wait都可以使用,但是通常情况下,您将使用waitpid;请参阅下面列出的文档。

子进程总是exit s,否则您将有多个进程执行程序中所有其余代码。子进程退出后,内核将通知父进程,父进程可以通过wait / waitpid来“拾取”该通知(“获得”子进程的退出状态),或使用信号处理程序忽略它。

如果父级在孩子退出后再也没有退出过,然后又退出自身,则OS将停留在进程表中有关(已退出)子进程的信息;那是僵尸。因此,您确实需要wait,以便操作系统可以完成子进程(并检查其运行方式)。或者,使用信号处理程序指示您不在乎孩子的出口。现代系统可能会成为僵尸,但并非总是如此,您不能依靠它。自己清理一下。

请注意,您需要阅读perlipcforkwaitwaitpidperlvar ...以及其他许多页面在处理所有这些时会遇到。这将需要一些时间和一些反复试验。一旦全部解决,您可能至少要对某些类型的任务开始使用模块。