分叉进程的正确方法是:每个进程运行一个不同的子例程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
。是否有一种干净简单的方法来解决它?
答案 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
,以便操作系统可以完成子进程(并检查其运行方式)。或者,使用信号处理程序指示您不在乎孩子的出口。现代系统可能会成为僵尸,但并非总是如此,您不能依靠它。自己清理一下。
请注意,您需要阅读perlipc,fork,wait和waitpid,perlvar ...以及其他许多页面在处理所有这些时会遇到。这将需要一些时间和一些反复试验。一旦全部解决,您可能至少要对某些类型的任务开始使用模块。