回调run_on_start
与每个新进程一起运行并且计数器递增。但回调run_on_finish
从不触发,所以计数器永远不会递减。因此,一旦它达到5
代码位于while
循环。请注意,父母和子女不能直接更改彼此的变量,作为单独的进程。
回调run_on_finish
通常在所有进程分叉后由wait_all_children
触发。当最大进程数量运行并且一个进程退出时,它的工作也完成了 。这通过致电wait_one_child
(其调用on_finish
,见下文)在start
中完成。
或者,这可以通过调用reap_finished_children
方法
这是一个非阻塞调用来获得孩子和执行回调独立呼叫到start
或wait_all_children
来完成。在不经常调用start
的情况下使用它,但您希望快速执行回调。
这解决的主要关注如何沟通个别孩子退出(如在评论澄清),而不是由wait_all_children
。
下面是一个如何使用它的示例,以便在小孩退出时回调正确运行。
使用这种方法相当于后fork
-ing调用waitpid -1, POSIX::WNOHANG
在一个循环。这比最大(30
)进程分叉要更容易看到输出并且证明回调在小孩退出时正确运行。更改这些数字以查看其完整操作。
大量的代码用于诊断。我们用10*$i
退出,以跟踪输出中的儿童。出于同样的目的,匿名数组[...]
中返回的数据是一个描述性字符串。一旦reap_finished_children
完成$number_running
减少,在回调。这就是为什么我们需要$curr
变量(再次用于诊断)。
这将打印
start: Started 4656, running: 1
start: Started 4657, running: 2
start: Started 4658, running: 3
Running: 4656 4658 4657
Kid #1 slept for 1, exiting
Cleared 4656, kid #1 exited with 10
Remains: 2. Data: gone-4656
Kid #2 slept for 10, exiting
Cleared 4657, kid #2 exited with 20
Remains: 1. Data: gone-4656 gone-4657
Kid #3 slept for 20, exiting
Cleared 4658, kid #3 exited with 30
Remains: 0. Data: gone-4656 gone-4657 gone-4658
的直接问题是如何等待整批来开始新的之前完成。这可以直接通过wait_for_available_procs($n)
等到$n
可用的进程插槽可用。如果未给出$n
,则默认为。
如果$MAX
用于$n
,那么许多插槽只有在整批完成后才可用。在运行时也可以决定使用什么$n
。
当一个孩子离开SIGCHLD
信号被发送到父,它必须为了赶上模块操作的一些细节就知道孩子走了(并避免僵尸,首先)。这是通过在代码中或在SIGCHLD
处理程序中使用wait
或waitpid
(但仅在一个地方)完成的。参见fork
,Signals in perlipc
,waitpid
和wait
。
我们从P::FM's source
看到,这是在完成wait_one_child
(经由_waitpid
子)
sub wait_one_child { my ($s,$par)[email protected]_;
my $kid;
while (1) {
$kid = $s->_waitpid(-1,$par||=0);
last if $kid == 0 || $kid == -1; # AS 5.6/Win32 returns negative PIDs
redo if !exists $s->{processes}->{$kid};
my $id = delete $s->{processes}->{$kid};
$s->on_finish($kid, $? >> 8 , $id, $? & 0x7f, $? & 0x80 ? 1 : 0);
last;
}
$kid;
};
其在wait_all_children
sub wait_all_children { my ($s)[email protected]_;
while (keys %{ $s->{processes} }) {
$s->on_wait;
$s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
};
}
的方法,使用上面使用的0是这种方法的同义词。
获取信号的方法wait_one_child
被start
用于在最大进程数已满并且有一个退出时收获子进程。这是模块如何知道何时可以启动另一个进程并尊重其最大值的方式。 (它也被一些等待进程的其他例程使用, )。这是当run_on_finish
被触发,通过$s->on_finish($kid, ...)
sub on_finish {
my ($s,$pid,@par)[email protected]_;
my $code=$s->{on_finish}->{$pid} || $s->{on_finish}->{0} or return 0;
$code->($pid,@par);
};
回调是在CODEREF $code
,从对象的on_finish
键,这本身就是在子run_on_finish
设定检索。一旦子运行,这就是回调的设置方式。
用于此目的的方法是wait_all_children
和reap_finished_children
。
由于没有在发布的代码中使用这个$number_running
没有得到更新所以while
是一个无限循环。回想一下,父级中的变量$number_running
不能通过子进程直接更改。
你不应该在这样的空闲循环中旋转。您的父进程将耗尽所有CPU时间,并无休止地测试'$ number_running'的值。 – Borodin
如何等待'$ number_running'由子进程递减至零? – CJ7
@ CJ7子进程不会影响在父子进程中使用的$ number_running,并且父进程不能写入彼此的变量。父母必须为自己减少这个变量。请参阅我的答案中添加的解释。 – zdim