将SIGINT(^ C)发送到包含子代的perl脚本时会发生什么情况? [英] What happens to a SIGINT (^C) when sent to a perl script containing children?

查看:115
本文介绍了将SIGINT(^ C)发送到包含子代的perl脚本时会发生什么情况?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个派生的Perl脚本.

I have a Perl script that forks.

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

Each fork runs an external program, parses the output, and converts the output to a Storable file.

然后,父级读取Storable文件,并分析每个子级的总数据,然后再重复上一个fork,否则父级停止.

The Storable files are then read in by the parent and the total data from each of the children are analyzed before proceeding onto a repeat of the previous fork or else the parent stops.

当某些孩子仍在运行外部程序时发出^ C时,会发生什么情况?父perl脚本在前台被调用,我想尽管有分叉,但仍在前台.

What exactly happens when I issue a ^C while some of the children are still running the external program? The parent perl script was called in the foreground and, I presume, remained in the foreground despite the forking.

SIGINT是否传递给所有子代,即父代,父代的子代以及子代调用的外部程序?

Is the SIGINT passed to all children, that is, the parent, the parent's children, and the external program called by the children??

更新:

我应该补充一点,看来当我发布SIGINIT时,脚本子级调用的外部程序似乎可以确认信号并终止.但是,孩子们,或者也许是父程序,仍在继续.这对我来说还不清楚.

I should add, it appears that when I issue the SIGINIT, the external program called by the children of my script seem to acknowledge the signal and terminate. But the children, or perhaps the parent program, carry on. This is all unclear to me.

更新2 :

关于tchrist的注释,使用Perl的system()命令调用外部程序.

With respect to tchrist's comment, the external program is called with Perl's system() command.

事实上,tchrist的评论似乎也包含了我所寻找的解释.经过一些调试之后,根据我的程序的行为,似乎确实将SIGINT从父级传递给了所有子级,并且从所有子级传递给了所有子级(外部程序).

In fact, tchrist's comment also seems to contain the explanation I was looking for. After some more debugging, based on the behavior of my program, it appears that, indeed, SIGINT is being passed from the parent to all children and from all children to all of their children (the external program).

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

Thus, what appears to be happening, based on tchrist's comment, is that CTRL-C is killing the external program which causes the children to move out of the system() command - and nothing more.

尽管我让我的孩子检查了system()中所谓的退出状态,但我假设CTRL-C会杀死从父级到下游的所有内容,而不是导致创建更多回合处理,是怎么回事!!!

Although I had my children check the exit status of what was called in system(), I was assuming that a CTRL-C would kill everything from the parent down, rather than lead to the creation of more rounds of processing, which is what was happening!!!

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

我只需要在父级中为SIGINT创建一个信号处理程序.然后,信号处理程序将SIGTERM发送给每个孩子(我想还将向孩子的孩子发送SIGTERM),然后使父项正常退出.尽管这种看似明显的解决方案可能会解决一些问题,但我还是想了解我对SIGINT在Perl中进行分叉的行为的误解.

I need to just create a signal handler for SIGINT in the parent. The signal handler would then send SIGTERM to each of the children (which I presume would also send a SIGTERM to the children's children), and then cause the parent to exit gracefully. Although this somewhat obvious solution likely would have fixed things, I wanted to understand my misconception about the behavior of SIGINT with respect to forking in Perl.

推荐答案

Perl的内置system函数的作用与标准C库中的C system (3)函数一样,只是信号有所不同.担心的.如果您使用的是Perl版本的system()或管道打开或反引号,则父级(一个调用system而不是它调用的)将在子级运行时忽略任何SIGINT和SIGQUIT.如果您使用了fork?wait:exec三重奏的某些变体来进行自己的滚动,那么您必须自己考虑这些问题.

Perl’s builtin system function works just like the C system(3) function from the standard C library as far as signals are concerned. If you are using Perl’s version of system() or pipe open or backticks, then the parent — the one calling system rather than the one called by it — will IGNORE any SIGINT and SIGQUIT while the children are running. If you’ve you rolled your own using some variant of the fork?wait:exec trio, then you must think about these matters yourself.

请考虑使用system("vi somefile")并在vi中进行长时间搜索时按^ C会发生什么:只有vi会接收(非致命的)SIGINT;父母会忽略它.这是正确的行为.这就是C如此工作的原因,也是Perl如此工作的原因.

Consider what happens when you use system("vi somefile") and hit ^C during a long search in vi: only vi takes a (nonfatal) SIGINT; the parent ignores it. This is correct behavior. That’s why C works this way, and that’s why Perl works this way.

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

The thing you have to remember is that just because a ^C sends a SIGINT to all processes in the foregrounded process group (even those of differing effective UID or GID), that does not mean that it causes all those processes to exit. A ^C is only a SIGINT, meant to interrupt a process, not a SIGKILL, meant to terminate with no questions asked.

有许多种程序,只是在没有警告的情况下将其杀死是错误的.编辑器就是这样一个例子.邮递员可能是另一个.对此要格外小心.

There are many sorts of program that it would be wrong to just kill off with no warning; an editor is just one such example. A mailer might be another. Be exceedingly careful about this.

许多程序有选择地忽略,捕获或阻止(意味着延迟传送)各种信号. SIGINT的默认行为是导致进程退出.使用传统操作系统上的此类代码,您可以找出是否发生了这种情况,以及实际上是由什么信号导致了这种情况的发生:

Many sorts of programs selectively ignore, trap, or block (means delay delivery of) various sorts of signals. Only the default behavior of SIGINT is to cause the process to exit. You can find out whether this happened, and in fact which signal caused it to happen (amongst other things), with this sort of code on traditional operating systems:

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,因为没有一个:它捕获了它

Note carefully that a ^C’d vi, for example, will not have a wait status word indicating it died from an untrapped SIGINT, since there wasn’t one: it caught it.

有时候,您的孩子会去背对背自己的孩子.凌乱但真实.因此,有时我会以这种方式种族灭绝所有已知和未知的子代:

Sometimes your kids will go and have kids of their own behind your back. Messy but true. I have therefore been known, on occasion, to genocide all progeny known and unknown this way:

# scope to temporize (save+restore) any previous value of $SIG{HUP}
{
    local $SIG{HUP} = "IGNORE";
    kill HUP => -$$;   # the killpg(getpid(), SIGHUP) syscall
}

这当然不适用于SIGKILL或SIGSTOP,它们不适合这样被忽略.

That of course doesn’t work with SIGKILL or SIGSTOP, which are not amenable to being IGNOREd like that.

您可能要注意的另一件事是,在5.8版本之前,Perl中的信号处理历来并不是可靠的安全操作.现在是现在,但这是一个与版本有关的问题.如果您尚未这样做,那么绝对应该阅读 perlipc 联机帮助页中以及在 PERL_SIGNALS perlrun 联机帮助页中是不变的.

Another matter you might want to be careful of is that before the 5.8 release, signal handling in Perl has not historically been a reliably safe operation. It is now, but this is a version-dependent issue. If you haven’t yet done so, then you should definitely read up on deferred signals in the perlipc manpage, and perhaps also on the PERL_SIGNALS envariable in the perlrun manpage.

这篇关于将SIGINT(^ C)发送到包含子代的perl脚本时会发生什么情况?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆