AberSheeran
Aber Sheeran

Python signal

起笔自
所属文集: Python-Package
共计 1380 个字符
落笔于

signal 提供了跨平台的信号处理能力,但信号机制在不同系统上却有很大的差异。Python 没有处理一些本可以处理的不同,于是给使用者留下了一点隐藏的问题。

信号的跨平台差异

SIGINT/SIGTERM

这是两个常常出现的信号,它们的处理函数往往被加入进程退出的程序。在 Unix 和 Windows 上都可以给它们注册对应的信号处理函数,发送却完全不同。

在 Windows 上给一个进程发送 SIGINT 信号,你应该使用的是 signal.CTRL_C_EVENT,而不是像在 Unix 上一样使用 signal.SIGINT。虽然你可以在 Windows 上调用 os.kill(pid, signal.SIGINT),但它没有你想要的作用。

SIGTREM 虽然在 Windows 上被定义了,但只允许进程使用 raise(注意不是 Python 的 raise 语法) 给自己抛出。这意味着你无法让一个进程给另一个进程发送 SIGTERM 信号来触发对应的处理函数。在 Windows 上,Python 进程想给本进程发送一个 SIGTERM 信号可以使用 signal.raise_signal(signal.SIGTERM)

SIGBREAK

这是一个 Windows 上独有的信号,由 CTRL+BRAEK 键触发,它类似于 CTRL+C 触发的 SIGINT,区别在于 SIGINT 的默认处理程序是抛出一个 KeyboardInterrupt 异常。

你可以通过 os.kill(pid, signal.CTRL_BREAK_EVENT) 的方式向共享同一个控制台的进程发送 SIGBREAK 信号。

当你在 Windows 控制台使用 CTRL+BRAEKCTRL+C 触发对应的信号时要注意,这些信号会传递到与控制台连接的所有控制台进程

其他信号

除了上述三个信号外,SIGILL/SIGSEGV/SIGABRT 也是 Windows 上支持的信号,但一般来说它们并不需要被用户程序处理。

Windows 平台只有这六种信号,其他信号无需考虑 Windows 平台的兼容性,使用起来也较为简单,不多赘述。

注册信号处理函数

在 C 语言里编写信号处理逻辑,当信号被处理过一次之后,需要重新注册信号处理函数。而在 Python 里不需要,因为 Python 替你重新注册了。

对同一个信号多次注册处理函数时,Python 只会留下最后一次注册的处理函数。这里就存在一个小技巧,比如处理 SIGINT 信号的时候,用户不停按 Ctrl+C 应该是非常急切的想要关闭。那么第一次触发信号之后,我们可以注册一个新的信号处理函数用于处理快速退出。

import signal


def f0(signum, frame):
    print("Interrupted")
    signal.signal(signal.SIGINT, lambda signum, frame: print("SIGINT"))


signal.signal(signal.SIGINT, f0)

while True:
    import time

    time.sleep(1)
如果你觉得本文值得,不妨赏杯茶
Python asyncio
没有下一篇