Python signal.signal是否阻止了传播?

时间:2014-02-18 14:28:40

标签: python signals interrupt

所以我有这段代码(部分取自python docs):

import signal

def handler(signum, frame):
    print 'Signal handler called with signal', signum

s = signal.signal(signal.SIGINT, handler)

some_fancy_code() # this code is using subprocess.Popen() to call another script

singal.signal(signal.SIGINT, s)

我现在发现的是,如果我在程序中执行Ctrl + C,它会正确输入该处理程序并进行打印。现在,我认为在收到Ctrl + C之后,我的处理程序将禁止默认处理程序,例如我的subprocess.Popen将不会获得KeyboardInterrupt信号。但事实并非如此。

但是当我们用'signal.SIG_IGN'替换'handler'时,这种传播永远不会发生。修改后的代码段:

import signal

s = signal.signal(signal.SIGINT, signal.SIG_IGN)

some_fancy_code() # this code is using subprocess.Popen() to call another script

singal.signal(signal.SIGINT, s)

这是因为SIG_IGN是用语言本身写的某种“神奇”信号吗?或者也许有一种方法可以在我自己的处理程序中进行类似的抑制?

在阅读了关于堆栈溢出的一些问题后,我有点困惑。如果有人能告诉我为什么会出现这种差异。

1 个答案:

答案 0 :(得分:2)

这是信号的指定POSIX行为:

   A child created via fork(2) inherits a copy of its parent's signal dis‐
   positions.  During an execve(2), the dispositions  of  handled  signals
   are  reset to the default; the dispositions of ignored signals are left
   unchanged.

当您在第一种情况下执行(fork / execve)另一个脚本时,SIGINT处理程序将重置为另一个脚本中的默认处理程序(默认行为是终止进程) - 当然,另一个脚本可以安装它自己的处理程序并改变这种行为。

但是,在第二种情况下,您已将SIGINT配置为被忽略。此行为将传播到另一个脚本,如上面的定义所示。同样,另一个脚本可以通过安装自己的处理程序来改变这种行为。

所以这与Python直接无关。这是底层操作系统的POSIX信号处理实现的预期行为。

PS。如果您想知道fork()和execve()是什么,fork()会创建正在运行的进程(子进程)的副本,而execve()会替换当前进程另一个。这是subprocess.Popen()用于运行“另一个脚本”的基础机制:首先制作当前进程的副本,然后将其替换为目标进程。