假设你的perl
有semop
和 的朋友,你可以使用System V信号量在孩子之间进行同步。下面的 为一个工作示例程序。
我们从平常的事情开始。代码使用内置的 IPC::SysV和 IPC::Semaphore模块,而不是直接调用低级别信号量操作。
#! /usr/bin/env perl
use strict;
use warnings;
use IPC::Semaphore;
use IPC::SysV qw/ IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT /;
该程序将子进程分成两个阶段。儿童在 第一阶段运行完成,执行他们的处理没有 同步问题。我们可以有任意许多这些。
我们有一个第二阶段的过程,但它执行毕竟 第一阶段的孩子已经完成。
下面是简单的占位符实现。
# how many other children the last child must wait for
my $FIRST_STAGE_CHILDREN = 2;
sub first_stage {
my($id) = @_;
print "[$$] hello from child $id\n";
sleep rand 10;
print "[$$] child $id done\n";
}
sub second_stage {
print "[$$] hello from second-stage child!\n";
}
为了实现第一和第二阶段之间的同步,所述 程序创建一组信号量的,其大小等于 第一级的儿童的数量。当第一阶段孩子完成时,程序 释放与该孩子相对应的特定信号量。
my $sem = IPC::Semaphore->new(
IPC_PRIVATE, $FIRST_STAGE_CHILDREN,
S_IRUSR | S_IWUSR | IPC_CREAT)
or die "$0: failed to create semaphore: $!";
稍后我们会看到,第二阶段的孩子通过 试图减小他们的信号灯等待他的弟兄们。当第二阶段孩子尝试这些减量时,通过将值设为零开始, ,操作系统将让孩子睡觉,因为。只有在所有第一阶段的孩子退出并释放信号后 才会阻止 第二阶段的孩子。
# start in blocked state
$sem->setall((0) x $FIRST_STAGE_CHILDREN);
首先我们fork
第一阶段的孩子。在这种设计中,父母 过程尽可能多地记账。这使first_stage
和second_stage
的定义 保持简单。另外,如果第一阶段的孩子以某种方式退出而没有释放其信号量,则第二阶段 不会有跑步的希望。
my %kids;
foreach my $id (0 .. $FIRST_STAGE_CHILDREN - 1) {
my $pid = fork;
die "$0: fork: $!" unless defined $pid;
if ($pid) {
++$kids{$pid};
}
else {
first_stage $id;
$sem->op($id, 1, 0); # release
exit 0;
}
}
现在我们分叉第二阶段的孩子。重要提示:尽管代码 对多个信号量执行操作,但原子上会发生, ,也就是说,它可以适用于所有这些信号,也可以不适用于它们。在没有 可观察到的状态下,它会显示第二阶段能够抢占第一阶段信号量的任何少于全部的 。这是一个重要的 属性。在更复杂的系统中,随意发布和释放将导致死锁。
my $pid = fork;
die "$0: fork: $!" unless defined $pid;
if ($pid) {
++$kids{$pid};
}
else {
# block waiting on all first-stage children
my @op = map +($_, -1, 0), 0 .. $FIRST_STAGE_CHILDREN - 1;
$sem->op(@op);
second_stage;
exit 0;
}
最后,父进程等待所有孩子完成。
do {
$pid = waitpid -1, 0;
print "[$$] reaped $pid\n";
warn "$0: unknown child $pid" unless delete $kids{$pid};
} while $pid > 0 && keys %kids;
样本输出如下。观看现场可以看到停顿更有趣。
[18389] hello from child 0
[18390] hello from child 1
[18390] child 1 done
[18388] reaped 18390
[18389] child 0 done
[18391] hello from second-stage child!
[18388] reaped 18389
[18388] reaped 18391
你可以让父母等待child1在产卵之前完成child2吗?是否有要求在child1完成之前产生child2? – Joel
我之所以需要等待,是因为产卵后的父母所做的事情在时间上有些敏感。 –