gpt4 book ai didi

perl - 当发送到包含子级的 perl 脚本时,SIGINT (^C) 会发生什么?

转载 作者:行者123 更新时间:2023-12-03 21:24:33 25 4
gpt4 key购买 nike

我有一个 fork 的 Perl 脚本。

每个 fork 运行一个外部程序,解析输出,并将输出转换为可存储文件。

然后可存储文件由父级读入,并在继续前一个 fork 的重复之前分析来自每个子级的总数据,否则父级将停止。

当我发出 ^C 而一些 child 仍在运行外部程序时究竟会发生什么?父 perl 脚本在前台被调用,我认为,尽管进行了 fork ,但它仍保留在前台。

SIGINT 是否传递给所有的 child ,也就是 parent , parent 的 child , child 调用的外部程序??

更新 :

我应该补充一点,当我发出 SIGINIT 时,我的脚本的子进程调用的外部程序似乎确认了信号并终止。但是 children ,或者可能是家长计划,继续进行。这一切我都不清楚。

更新 2 :

关于tchrist的评论,外部程序是用Perl的system()调用的命令。

事实上,tchrist 的评论似乎也包含了我正在寻找的解释。经过一些更多的调试,根据我的程序的行为,似乎确实,SIGINT 正在从父级传递给所有子级,并从所有子级传递给它们的所有子级(外部程序)。

因此,根据 tchrist 的评论,似乎正在发生的事情是 CTRL-C 正在杀死导致 child 移出 system() 的外部程序。命令 - 仅此而已。

尽管我让我的 child 检查了 system() 中调用的退出状态,我假设 CTRL-C 会杀死从父级向下的所有内容,而不是导致创建更多轮处理,这就是正在发生的事情!!!

解决方案(针对我的问题) :

我只需要在父级中为 SIGINT 创建一个信号处理程序。信号处理程序然后将 SIGTERM 发送给每个 child (我认为它也会向 child 的 child 发送一个 SIGTERM ),然后使 parent 优雅地退出。虽然这个有点明显的解决方案可能会修复一些问题,但我想了解我对 SIGINT 在 Perl 中 fork 的行为的误解。

最佳答案

Perl 的内置 system就信号而言,函数就像标准 C 库中的 C system(3) 函数一样工作。如果您使用的是 Perl 版本的 system()或管道打开或反引号,然后是父级 - 调用 system 的那个而不是它调用的那个——当 children 正在运行时会忽略任何 SIGINT 和 SIGQUIT。如果您已经使用 fork?wait:exec 的某些变体推出了自己的产品三人组,那么这些事情你自己要考虑清楚。

考虑使用 system("vi somefile") 时会发生什么并在 vi 的长时间搜索中点击 ^C : 仅 vi需要一个(非致命的)信号; parent 忽略它。这是正确的行为。这就是 C 以这种方式工作的原因,也是 Perl 以这种方式工作的原因。

您必须记住的是,仅仅因为 ^C 向前台进程组中的所有进程(即使是那些具有不同有效 UID 或 GID 的进程)发送一个 SIGINT,才不是 意味着它会导致所有这些进程退出。 ^C 只是一个 SIGINT,意味着 中断一个进程,而不是 SIGKILL,意味着在不问任何问题的情况下终止。

有很多种程序,在没有警告的情况下直接终止是错误的;编辑器就是这样的一个例子。邮件程序可能是另一个。对此要格外小心。

许多类型的程序选择性地忽略、捕获或阻止(意味着延迟传递)各种类型的信号。只有 SIGINT 的默认行为是导致进程退出。您可以使用传统操作系统上的此类代码找出这是否发生,以及实际上是哪个信号导致它发生(除其他外):

if ($wait_status = system("whatever")) {
$sig_killed = $wait_status & 127;
$did_coredump = $wait_status & 128;
$exit_status = $wait_status >> 8;
# now do something based on that...
}

仔细注意 ^C'd vi例如,将 不是 有一个等待状态字,表明它死于一个未捕获的 SIGINT,因为没有一个:它捕获了它。

有时你的 child 会去,在你背后拥有自己的 child 。凌乱但真实。因此,我有时会以这种方式灭绝所有已知和未知的后代:
# scope to temporize (save+restore) any previous value of $SIG{HUP}
{
local $SIG{HUP} = "IGNORE";
kill HUP => -$$; # the killpg(getpid(), SIGHUP) syscall
}

这当然不适用于 SIGKILL 或 SIGSTOP,它们不能像那样被忽略。

您可能需要注意的另一件事是,在 5.8 版本之前,Perl 中的信号处理在历史上并不是可靠的安全操作。是 现在 ,但这是一个版本相关的问题。如果您还没有这样做,那么您绝对应该阅读 deferred signals in the perlipc manpage ,也许还有 PERL_SIGNALS envariable in the perlrun manpage .

关于perl - 当发送到包含子级的 perl 脚本时,SIGINT (^C) 会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4717118/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com