所以我有这段代码(部分取自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是用语言本身写的某种“神奇”信号吗?或者也许有一种方法可以在我自己的处理程序中进行类似的抑制?
在阅读了关于堆栈溢出的一些问题后,我有点困惑。如果有人能告诉我为什么会出现这种差异。
答案 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()用于运行“另一个脚本”的基础机制:首先制作当前进程的副本,然后将其替换为目标进程。