假设我有以下脚本:
import signal
import sys
class Klass:
def __init__(self, name):
self.name = name
def disconnect_gracefully(*args):
print(self.name)
sys.exit()
signal.signal(signal.SIGINT, disconnect_gracefully)
a = Klass("A")
b = Klass("B")
while True:
pass
请注意,这两个类在 SIGINT 后都会正常退出。当我运行这个和 crtl-c 时,只打印“B”。
一般来说,在这种情况下,who或what应该调用
sys.exit()
- 两种情况都应该调用吗?
signal的Python文档仅说明了多次为同一信号设置处理程序时会发生什么:
特定信号的处理程序一旦设置,就会保持安装状态,直到明确重置为止
和
[调用时
]将返回之前的信号处理程序signal.signal
这似乎意味着,就像 POSIX 信号一样,一个进程一次只能有一个给定信号的处理程序。
我们可以在您的程序中添加一些语句来显示
signal.signal
返回什么(在 CPython 中):
import signal
import sys
class K:
def __init__(self, name):
self.name=name
def disconnect(*args):
print(self.name)
sys.exit()
self.disconnectfuncid=id(disconnect)
self.oldsig=signal.signal(signal.SIGINT, disconnect)
>>> a=K("a")
>>> hex(a.disconnectfuncid)
'0x7fc5c1057f28'
>>> a.oldsig
<built-in function default_int_handler>
>>> signal.getsignal(signal.SIGINT)
<function K.__init__.<locals>.disconnect at 0x7fc5c1057f28>
>>> b=K("b")
>>> hex(b.disconnectfuncid)
'0x7fc5c0ed0950'
>>> b.oldsig
<function K.__init__.<locals>.disconnect at 0x7fc5c1057f28>
>>> signal.getsignal(signal.SIGINT)
<function K.__init__.<locals>.disconnect at 0x7fc5c0ed0950>
>>> while True:
... pass
...^C b
因此,处理程序以
<built-in function default_int_handler>
开始,然后设置为 disconnect
实例中的 a
函数,然后设置为 disconnect
实例中的 b
函数,后者就是被调用的函数当信号发出时。
如果您想在收到 SIGINT 时退出,并在退出前运行多个函数,一种方法是调用以下命令(这将抑制打印回溯和
KeyboardInterrupt
消息):
signal.signal(signal.SIGINT, lambda *args: sys.exit())
然后使用 atexit.register 注册每个函数。
已经创建了这个要点(但这只有在到处使用或至少最终使用 register_signal_handler 时才有效)
https://gist.github.com/SuperThinking/ba07424e86308faaf2ab533a75d2bbc6