我试图决定从为x86_64-
linux-thread-multi构建的perl(v5.14.2)中的信号处理程序访问公共(读取:处理程序代码和程序的其余部分之间的共享)数据结构是否安全,但目标平台是solaris11).
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); # ... } }
因此,从while循环和处理程序访问%children.这似乎没有问题,因为:
>不会有两个进程具有相同的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; # ... } }
@R_404_323@
对我来说似乎是一个坏主意. 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}在处理程序中将不存在.等等,是的,你必须同步.