4

我正在尝试确定从为 构建的 perl (v5.14.2) 中的信号处理程序访问公共(读取:在处理程序代码和程序的其余部分之间共享)数据结构是否安全x86_64-linux-thread-multi,但目标平台是 solaris11)。

perlipc有以下示例代码:

use POSIX ":sys_wait_h"; # for nonblocking read
my %children;
$SIG{CHLD} = sub {
    # don't change $! and $? outside handler
    local ($!, $?);
    my $pid = waitpid(-1, WNOHANG);
    return if $pid == -1;
    return unless defined $children{$pid};
    delete $children{$pid};
    cleanup_child($pid, $?);
};
while (1) {
    my $pid = fork();
    die "cannot fork" unless defined $pid;
    if ($pid == 0) {
        # ...
        exit 0;
    } else {
        $children{$pid}=1;
        # ...
        system($command);
        # ...
   }
}

因此,%children从 while 循环和处理程序访问。这似乎没有问题,因为:

  1. 不会有两个进程相同pid
  2. 访问是由pid(但我不确定是否$childer{pid}=1是原子的和可中断的而不会导致损坏。)

现在,我正在尝试在我的处理程序中做更多的事情:

my %categoryForPid;
my %childrenPerCategory;

$SIG{CHLD} = sub {
    # ... acquire pid like above
    my $category = $categoryForPid{$pid};
    $childrenPerCategory{$category}--;
    delete $categoryForPid{$pid};
}

while (1) {
    # ... same as above
    } else {
        $children{$pid}=1;
        my $category = # ... chose some how
        $childrenPerCategory{$category}++;
        $categoryForPid{$pid} = $category;
        # ...
    }
}

这里的想法是:每个孩子都属于某个类别(N 到 1)。我想跟踪每个类别有多少孩子。该信息可能来自$categoryForPid,但我认为这也可能是有问题的(例如,当进行计算的子程序在总结时被中断)。

所以我的问题是:

  • 我需要以某种方式在这里同步吗?

附带说明:

  • 在 perl 5.12 中是否可以嵌套调用信号处理程序,或者它们是否被解释器线性化?

更新

除了@goldilocks 和他提出的解决方案发现的问题之外,我现在在更新数据结构以确保“原子性”时阻止信号:

my $sigset = POSIX::SigSet->new(SIGCHLD);

sub ublk {
    unless (defined sigprocmask(SIG_UNBLOCK, $sigset)) {
        die "Could not unblock SIGCHLD\n";
    }
}

sub blk {
    unless (defined sigprocmask(SIG_BLOCK, $sigset)) {
        die "Could not block SIGCHLD\n";
    }
}

while (1) {
    # ... same as above
    } else {
         blk;
         $children{$pid}=1;
         my $category = # ... chose some how
         $childrenPerCategory{$category}++;
         $categoryForPid{$pid} = $category;
         ublk;
         # ...
    }
}
4

1 回答 1

1

对我来说似乎是个坏主意。 IPC::Semaphore 可能会解决这个问题,如果你能让它们在信号处理程序中正常工作——如果控制在处理程序退出之前没有返回,那么你就不走运了。但是,您可以通过锁定父项并让子项等待锁定直到初始化完成来解决此问题;处理程序不涉及信号量。我想你实际上只需要一把锁。反正:

my @array = (1..10);
my $x = 'x';

$SIG{'USR1'} = sub {
    print "SIGUSER1\n";
    undef @array;
    $x = '!!';
};

print "$$\n";

foreach (@array) {
    print "$_:\n";
    sleep(2);
    print "\t$x\n";
    print "\t$array[$_ - 1]\n";
}

毫不奇怪,这样做:

2482
1:
    x
    1
2:
    x
    2
3:
SIGUSER1
    !!
Use of uninitialized value within @array in concatenation (.) or string at ./test.pl line 42.

暗示如果你此时捕捉到信号:

    my $category = # ... chose some how

$categoryForPid{$pid}处理程序中将不存在。等等。也就是说,是的,你必须同步。

于 2012-05-15T11:48:50.250 回答