加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl – 安全地从信号处理程序访问共享数据结构

发布时间:2020-12-16 06:13:00 所属栏目:大数据 来源:网络整理
导读:我试图决定从为x86_64- linux-thread-multi构建的perl(v5.14.2)中的信号处理程序访问公共(读取:处理程序代码和程序的其余部分之间的共享)数据结构是否安全,但目标平台是solaris11). perlipc有以下示例代码: use POSIX ":sys_wait_h"; # for nonblocking re
我试图决定从为x86_64- linux-thread-multi构建的perl(v5.14.2)中的信号处理程序访问公共(读取:处理程序代码和程序的其余部分之间的共享)数据结构是否安全,但目标平台是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);
        # ...
   }
}

因此,从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 SIGCHLDn";
    }
}

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

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

解决方法

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

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

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

print "$$n";

foreach (@array) {
    print "$_:n";
    sleep(2);
    print "t$xn";
    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}在处理程序中将不存在.等等,是的,你必须同步.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读