のために構築された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ループとハンドラーからアクセスされます。これは問題ないようです:
- 同じものを持つ2つのプロセスはありません
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
、それも問題になる可能性があると思います(たとえば、計算を実行しているサブルーチンが合計中に中断された場合)。
だから私の質問は:
- どういうわけかここで同期する必要がありますか?
ちなみに:
- シグナルハンドラのネストされた呼び出しはperl5.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;
# ...
}
}