每个fork运行外部程序,解析输出,并将输出转换为可存储文件.
然后由父母读取可存储的文件,并分析来自每个孩子的总数据,然后继续重复前一个分支,否则父节点停止.
当我发出^ C,而一些孩子仍在运行外部程序时究竟发生了什么?父进程脚本在前台调用,我认为,尽管分叉仍然保留在前台.
SIGINT是否传递给所有的孩子,即父母,父母的孩子和孩子们调用的外部程序?
更新:
我应该补充一下,看起来当我发出SIGINIT时,我脚本的孩子所调用的外部程序似乎承认了信号并终止了.但孩子们,或者也许是父母节目,继续下去.这对我来说都不清楚
更新2:
关于tchrist的评论,使用Perl的system()命令调用外部程序.
事实上,tchrist的评论似乎也包含了我正在寻找的解释.经过一些更多的调试,根据我的程序的行为,看来,事实上,SIGINT正在从父代传递给所有的孩子,从所有的孩子传递给他们所有的孩子(外部程序).
因此,根据tchrist的评论,似乎正在发生的事情是,CTRL-C正在杀死导致孩子们离开system()命令的外部程序,而没有更多的东西.
虽然我有我的孩子检查系统()中调用的退出状态,但我假设CTRL-C会从父母身上杀死一切,而不是导致创建更多的处理,这是什么发生!
解决方案(对我的问题):
我需要在父节点创建SIGINT的信号处理程序.然后,信号处理程序将向每个孩子发送SIGTERM(我认为也会向孩子的孩子发送一个SIGTERM),然后使父母正常退出.虽然这个有点明显的解决方案可能会有固定的东西,但我想了解我对于SIGINT在Perl中的划分行为的误解.
解决方法
考虑在vi中长时间使用系统(“vi somefile”)并按^ C时会发生什么?只有vi需要(非致命的)SIGINT;父母忽略它.这是正确的行为.这就是为什么C以这种方式工作,这就是为什么Perl以这种方式工作的原因.
你必须记住的是,只是因为^ C向前台进程组(即使那些不同的有效UID或GID)的所有进程发送一个SIGINT,这并不意味着它会导致所有这些进程退出. A ^ 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,因为没有一个:它捕获它.
有时候,你的孩子们会去自己背后的孩子.凌乱但真实.因此,我有时候已经知道以这种方式种族灭绝所有已知和未知的后代:
# scope to temporize (save+restore) any prevIoUs value of $SIG{HUP} { local $SIG{HUP} = "IGNORE"; kill HUP => -$$; # the killpg(getpid(),SIGHUP) syscall }
那当然不符合SIGKILL或SIGSTOP的功能,这不符合IGNOREd的要求.
您可能想要注意的另一件事是,在5.8版本之前,Perl中的信号处理从来不是可靠的安全操作.现在是这个版本问题.如果你还没有这样做,那么你应该肯定会在deferred signals in the perlipc manpage上阅读,也许在PERL_SIGNALS
envariable in the perlrun manpage.