我正在尝试确定从为 构建的 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 循环和处理程序访问。这似乎没有问题,因为:
- 不会有两个进程相同
pid
- 访问是由
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;
# ...
}
}