On this page
signal —设置异步事件的处理程序
该模块提供了在 Python 中使用 signal 处理程序的机制。
General rules
signal.signal()函数允许定义自定义处理程序,以便在收到 signal 时执行。安装了少量默认处理程序:忽略SIGPIPE(因此可以将管道和套接字上的写入错误报告为普通的 Python 异常),并且如果父进程未将SIGINT转换为KeyboardInterrupt异常。
特定 signal 的处理程序(一旦设置)将保持安装状态,直到将其显式重置(Python 会模拟 BSD 样式接口,而不考虑基础实现),但SIGCHLD的处理程序除外,该处理程序遵循基础实现。
Pythonsignal 处理程序的执行
Pythonsignal 处理程序不会在底层(C)signal 处理程序中执行。相反,低级 signal 处理程序设置一个标志,该标志告诉virtual machine在以后的位置(例如,在下一条bytecode指令处)执行相应的 Pythonsignal 处理程序。结果是:
捕获由 C 代码中的无效操作引起的同步错误(如SIGFPE或SIGSEGV)几乎没有意义。 Python 将从 signal 处理程序返回到 C 代码,这很可能再次引发相同的 signal,从而导致 Python 显然挂起。从 Python 3.3 开始,您可以使用faulthandler模块报告同步错误。
纯粹以 C 语言实现的长时间运行的计算(例如,大文本正文上的正则表达式匹配)可以在任意时间内连续运行,而不管收到任何 signal。计算完成后,将调用 Pythonsignal 处理程序。
signal 和线程
即使在另一个线程中接收到 signal,Pythonsignal 处理程序也总是在主 Python 线程中执行。这意味着 signal 不能用作线程间通信的手段。您可以改为使用threading模块中的同步 Primitives。
此外,仅允许主线程设置新的 signal 处理程序。
Module contents
在版本 3.5 中进行了更改:将下面列出的与 signal(SIG *),处理程序(SIG_DFL,SIG_IGN)和 sigmask(SIG_BLOCK,SIG_UNBLOCK,SIG_SETMASK)相关的常量转换为enums。 getsignal(),pthread_sigmask(),sigpending()和sigwait()函数返回可读的enums。
signal模块中定义的变量是:
signal.
SIG_DFL
- 这是两个标准 signal 处理选项之一。它只会执行 signal 的默认Function。例如,在大多数系统上,
SIGQUIT
的默认操作是转储核心并退出,而SIGCHLD的默认操作是简单地忽略它。
- 这是两个标准 signal 处理选项之一。它只会执行 signal 的默认Function。例如,在大多数系统上,
signal.
SIG_IGN
- 这是另一个标准 signal 处理程序,它将简单地忽略给定的 signal。
signal.
SIGABRT
-
- abort(3) *中止 signal。
-
signal.
SIGALRM
- 来自* alarm(2) *的计时器 signal。
Availability: Unix.
signal.
SIGBREAK
- 键盘break(CTRL BREAK)。
Availability: Windows.
signal.
SIGBUS
- 总线错误(错误的内存访问)。
Availability: Unix.
signal.
SIGCHLD
- 子进程停止或终止。
Availability: Windows.
signal.
SIGCLD
- SIGCHLD的别名。
signal.
SIGCONT
- 如果当前已停止,则 continue 该过程
Availability: Unix.
signal.
SIGFPE
- 浮点异常。例如,除以零。
See also
当除法或模运算的第二个参数为零时,将引发ZeroDivisionError。
signal.
SIGHUP
- 在控制终端上检测到挂断或控制进程终止。
Availability: Unix.
signal.
SIGILL
- Illegal instruction.
signal.
SIGINT
- 键盘break(CTRL C)。
默认操作是加注KeyboardInterrupt。
signal.
SIGKILL
- Kill signal.
无法捕获,阻止或忽略它。
Availability: Unix.
signal.
SIGPIPE
- 管道损坏:在没有读取器的情况下写入管道。
默认操作是忽略 signal。
Availability: Unix.
signal.
SIGSEGV
- 分段错误:无效的内存引用。
signal.
SIGTERM
- Termination signal.
signal.
SIGUSR1
- 用户定义的 signal1.
Availability: Unix.
signal.
SIGUSR2
- 用户定义的 signal2.
Availability: Unix.
signal.
SIGWINCH
- 窗口调整大小 signal。
Availability: Unix.
SIG*
- 所有 signal 编号均以符号方式定义。例如,挂断 signal 定义为signal.SIGHUP;变量名与
<signal.h>
中的 C 程序中使用的名称相同。signal()
的 Unix 手册页列出了现有的 signal(在某些系统上是* signal(2) ,在其他系统上,列表在 signal(7) *中)。请注意,并非所有系统都定义相同的 signal 名称集。此模块仅定义系统定义的名称。
- 所有 signal 编号均以符号方式定义。例如,挂断 signal 定义为signal.SIGHUP;变量名与
signal.
CTRL_C_EVENT
- 与 Ctrl C 按键事件相对应的 signal。该 signal 只能与os.kill()一起使用。
Availability: Windows.
3.2 版中的新Function。
signal.
CTRL_BREAK_EVENT
- 与 Ctrl Break 击键事件相对应的 signal。该 signal 只能与os.kill()一起使用。
Availability: Windows.
3.2 版中的新Function。
signal.
NSIG
- 比最高 signal 编号多一。
signal.
ITIMER_REAL
- 实时减少间隔计时器,并在到期时发送SIGALRM。
signal.
ITIMER_VIRTUAL
- 仅在进程执行时才减小间隔计时器,并在到期时传递 SIGVTALRM。
signal.
ITIMER_PROF
- 在过程执行时以及系统代表过程执行时,都减小间隔计时器。与 ITIMER_VIRTUAL 结合使用时,该计时器通常用于分析应用程序在用户和内核空间中花费的时间。 SIGPROF 在到期时交付。
signal.
SIG_BLOCK
- pthread_sigmask()的* how *参数的可能值指示 signal 将被阻止。
版本 3.3 中的新Function。
signal.
SIG_UNBLOCK
- pthread_sigmask()的* how *参数的可能值指示 signal 将被解除阻塞。
版本 3.3 中的新Function。
signal.
SIG_SETMASK
- pthread_sigmask()的* how *参数的可能值,指示 signal 掩码将被替换。
版本 3.3 中的新Function。
signal模块定义了一个 exception:
- exception
signal.
ItimerError
- 引发 signal 来自底层的setitimer()或getitimer()实现。如果将无效的间隔计时器或负时间传递给setitimer(),则会出现此错误。此错误是OSError的子类型。
版本 3.3 中的新增Function:此错误曾经是IOError的子类型,现在是OSError的别名。
signal模块定义以下Function:
signal.
alarm
(时间)- 如果* time 不为零,则此函数要求在 time 秒内将SIGALRMsignal 发送到进程。任何先前计划的警报都会被取消(任何时候都只能计划一个警报)。然后,返回值是在传递任何先前设置的警报之前的秒数。如果 time *为零,则不会安排任何警报,并且任何计划的警报都会被取消。如果返回值为零,则当前未计划任何警报。
Availability:Unix。有关更多信息,请参见手册页* alarm(2) *。
signal.
getsignal
(* signalnum *)- 返回 signal* signalnum *的当前 signal 处理程序。返回的值可以是可调用的 Python 对象,也可以是特殊值signal.SIG_IGN,signal.SIG_DFL或None之一。在这里,signal.SIG_IGN表示先前已忽略 signal,signal.SIG_DFL表示先前已使用默认的 signal 处理方式,
None
表示未从 Python 安装以前的 signal 处理程序。
- 返回 signal* signalnum *的当前 signal 处理程序。返回的值可以是可调用的 Python 对象,也可以是特殊值signal.SIG_IGN,signal.SIG_DFL或None之一。在这里,signal.SIG_IGN表示先前已忽略 signal,signal.SIG_DFL表示先前已使用默认的 signal 处理方式,
signal.
strsignal
(* signalnum *)- 返回 signal* signalnum *的系统描述,例如“ Interrupt”,“ Segmentation fault”等。如果未识别到 signal,则返回None。
3.8 版的新Function。
signal.
valid_signals
( )- 返回此平台上的有效 signal 编号集。如果系统保留了一些 signal 供内部使用,则该值可以小于
range(1, NSIG)
。
- 返回此平台上的有效 signal 编号集。如果系统保留了一些 signal 供内部使用,则该值可以小于
3.8 版的新Function。
signal.
pause
( )- 使过程进入休眠状态,直到收到 signal 为止;然后将调用适当的处理程序。不返回任何内容。
Availability:Unix。有关更多信息,请参见手册页* signal(2) *。
另请参见sigwait(),sigwaitinfo(),sigtimedwait()和sigpending()。
signal.
raise_signal
(* signum *)- 向呼叫过程发送 signal。不返回任何内容。
3.8 版的新Function。
signal.
pthread_kill
(* thread_id , signalnum *)- 将 signal* signalnum 发送到线程 thread_id *,该线程与调用方的进程相同。目标线程可以执行任何代码(是否使用 Python)。但是,如果目标线程正在执行 Python 解释器,则 Pythonsignal 处理程序将为由主线程执行。因此,向特定的 Python 线程发送 signal 的唯一目的是强制正在运行的系统调用以InterruptedError失败。
使用threading.get_ident()或threading.Thread对象的ident属性为* thread_id *获取合适的值。
如果* signalnum *为 0,则不发送 signal,但仍执行错误检查;否则,将检查错误。这可用于检查目标线程是否仍在运行。
用参数thread_id
,signalnum
引发auditing event signal.pthread_kill
。
Availability:Unix。有关更多信息,请参见手册页* pthread_kill(3) *。
另请参见os.kill()。
版本 3.3 中的新Function。
signal.
pthread_sigmask
(方式,遮罩)- 获取和/或更改调用线程的 signal 掩码。signal 掩码是一组 signal,其当前已被呼叫者阻止。将旧的 signal 掩码作为一组 signal 返回。
调用的行为取决于* how *的值,如下所示。
SIG_BLOCK:被阻止 signal 的集合是当前集合和* mask *参数的并集。
SIG_UNBLOCK:* mask *中的 signal 已从当前阻塞 signal 集中删除。允许try解锁未被阻止的 signal。
SIG_SETMASK:被阻止的 signal 集被设置为* mask *参数。
- mask *是一组 signal 编号(例如 { signal.SIGINT , signal.SIGTERM })。使用valid_signals()表示包括所有 signal 的完整掩码。
例如,signal.pthread_sigmask(signal.SIG_BLOCK, [])
读取调用线程的 signal 掩码。
SIGKILL和SIGSTOP
无法被阻止。
Availability:Unix。有关更多信息,请参见手册* sigprocmask(3) 和 pthread_sigmask(3) *。
另请参见pause(),sigpending()和sigwait()。
版本 3.3 中的新Function。
signal.
setitimer
(* which , seconds , interval = 0.0 *)- 设置由哪个指定的给定间隔计时器(signal.ITIMER_REAL,signal.ITIMER_VIRTUAL或signal.ITIMER_PROF之一)在* seconds (接受浮点,不同于alarm())之后以及之后每个 interval 秒(如果 interval 不为零)触发)。可以pass将 seconds 设置为零来清除由哪个*指定的间隔计时器。
当间隔计时器触发时,signal 将发送到该进程。发送的 signal 取决于所使用的计时器。 signal.ITIMER_REAL将传送SIGALRM,signal.ITIMER_VIRTUAL将传送SIGVTALRM
,而signal.ITIMER_PROF将传送SIGPROF
。
旧值以 Tuples 形式返回:(延迟,间隔)。
trypass无效的间隔计时器将导致ItimerError。
Availability: Unix.
signal.
getitimer
(* which *)- 返回由* which *指定的给定间隔计时器的当前值。
Availability: Unix.
signal.
set_wakeup_fd
(* fd ,**,* warn_on_full_buffer = True *)- 将唤醒文件 Descriptors 设置为* fd *。接收到 signal 后,signal 编号将作为单个字节写入 fd。库可以使用它来唤醒轮询或选择调用,从而使 signal 得到充分处理。
返回旧的唤醒 fd(如果未启用文件 Descriptors 唤醒,则返回-1)。如果* fd 为-1,则禁用文件 Descriptors 唤醒。如果不为-1,则 fd 必须是非阻塞的。在调用 poll 或再次选择之前,库必须从 fd *中删除任何字节。
启用线程后,只能从主线程调用此函数;try从其他线程调用它会引发ValueError异常。
有两种使用此Function的常用方法。在这两种方法中,您都使用 fd 在 signal 到达时唤醒,但是它们在确定哪个signal 已经到达时的方式有所不同。
在第一种方法中,我们从 fd 的缓冲区中读取数据,字节值为您提供 signal 编号。这很简单,但在极少数情况下可能会出现问题:通常,fd 的缓冲区空间有限,并且如果太多 signal 到达得太快,则缓冲区可能变满,并且某些 signal 可能会丢失。如果使用此方法,则应设置warn_on_full_buffer=True
,这将在 signal 丢失时至少导致向 stderr 打印警告。
在第二种方法中,我们仅使用 wakeup fd * only *进行唤醒,而忽略实际的字节值。在这种情况下,我们关心的只是 fd 的缓冲区是空还是非空。完整的缓冲区根本不表示问题。如果使用此方法,则应设置warn_on_full_buffer=False
,以使用户不会被虚假警告消息所迷惑。
在版本 3.5 中进行了更改:在 Windows 上,该函数现在还支持套接字句柄。
在 3.7 版中进行了更改:添加了warn_on_full_buffer
参数。
signal.
siginterrupt
(* signalnum , flag *)- 更改系统调用重新启动行为:如果* flag 为False,则在被 signal signalnum *break时,系统调用将重新启动,否则系统调用将被break。不返回任何内容。
Availability:Unix。有关更多信息,请参见手册页* siginterrupt(3) *。
请注意,使用signal()安装 signal 处理程序将pass为给定 signal 隐式调用具有真实* flag *值的siginterrupt()
将重启行为重置为可break的。
signal.
signal
(* signalnum , handler *)- 将 signal* signalnum 的处理程序设置为函数 handler *。 * handler 可以是带有两个参数(请参见下文)或特殊值signal.SIG_IGN或signal.SIG_DFL之一的可调用 Python 对象。将返回之前的 signal 处理程序(请参见上面的getsignal()的描述)。 (有关更多信息,请参见 Unix 手册页 signal(2) *。)
启用线程后,只能从主线程调用此函数;try从其他线程调用它会引发ValueError异常。
使用两个参数调用* handler *:signal 编号和当前堆栈帧(None
或帧对象;有关帧对象的描述,请参见类型层次结构中的描述或在inspect模块中的属性描述)。
在 Windows 上,只能使用SIGABRT,SIGFPE,SIGILL,SIGINT,SIGSEGV,SIGTERM或SIGBREAK来调用signal()。在任何其他情况下,都将引发ValueError。请注意,并非所有系统都定义相同的 signal 名称集。如果 signal 名称未定义为SIG*
模块级常量,则将引发AttributeError。
signal.
sigpending
( )- 检查待传递给调用线程的 signal 集(即在阻塞时发出的 signal)。返回未决 signal 集。
Availability:Unix。有关更多信息,请参见手册页* sigpending(2) *。
另请参见pause(),pthread_sigmask()和sigwait()。
版本 3.3 中的新Function。
signal.
sigwait
(* sigset *)- 暂停调用线程的执行,直到传递 signal 集* sigset *中指定的 signal 之一为止。该函数接受 signal(将其从待处理的 signal 列表中删除),并返回 signal 编号。
Availability:Unix。有关更多信息,请参见手册页* sigwait(3) *。
另请参见pause(),pthread_sigmask(),sigpending(),sigwaitinfo()和sigtimedwait()。
版本 3.3 中的新Function。
signal.
sigwaitinfo
(* sigset *)- 暂停调用线程的执行,直到传递 signal 集* sigset 中指定的 signal 之一为止。该函数接受 signal 并将其从挂起的 signal 列表中删除。如果 sigset 中的 signal 之一已在 await 调用线程处理,则该函数将立即返回有关该 signal 的信息。不会为传递的 signal 调用 signal 处理程序。如果该 signal 被不在 sigset *中的 signal break,则该函数将引发InterruptedError。
返回值是表示siginfo_t
结构中包含的数据的对象,即si_signo
,si_code
,si_errno
,si_pid
,si_uid
,si_status
,si_band
。
Availability:Unix。有关更多信息,请参见手册页* sigwaitinfo(2) *。
另请参见pause(),sigwait()和sigtimedwait()。
版本 3.3 中的新Function。
在版本 3.5 中进行了更改:现在,如果被不在* sigset *中的 signal break并且该 signal 处理程序没有引发异常(请参阅 PEP 475),现在可以重试该函数。
signal.
sigtimedwait
(* sigset , timeout *)- 类似于sigwaitinfo(),但是需要额外的* timeout 参数来指定超时。如果将 timeout *指定为
0
,则执行轮询。如果发生超时,则返回None。
- 类似于sigwaitinfo(),但是需要额外的* timeout 参数来指定超时。如果将 timeout *指定为
Availability:Unix。有关更多信息,请参见手册页* sigtimedwait(2) *。
另请参见pause(),sigwait()和sigwaitinfo()。
版本 3.3 中的新Function。
在版本 3.5 中进行了更改:现在,如果被不在* sigset 中的 signal break并且 signal 处理程序没有引发异常,则该函数将使用重新计算的 timeout *重试(signal 原理请参见 PEP 475)。
Example
这是一个最小的示例程序。它使用alarm()函数来限制 await 打开文件所花费的时间;如果该文件用于可能无法打开的串行设备,这通常会导致os.open()无限期挂起,则这很有用。解决的办法是在打开文件之前设置 5 秒警报。如果操作时间太长,则会发送警报 signal,并且处理程序会引发异常。
import signal, os
def handler(signum, frame):
print('Signal handler called with signal', signum)
raise OSError("Couldn't open device!")
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)
signal.alarm(0) # Disable the alarm
关于 SIGPIPE 的注意事项
当将其标准输出的接收器提早关闭时,将程序的输出管道输出到* head(1) *之类的工具将导致SIGPIPEsignal 发送到您的进程。这会导致类似BrokenPipeError: [Errno 32] Broken pipe
的异常。要处理这种情况,请包装您的入口点以捕获此异常,如下所示:
import os
import sys
def main():
try:
# simulate large output (your code replaces this loop)
for x in range(10000):
print("y")
# flush output here to force SIGPIPE to be triggered
# while inside this try block.
sys.stdout.flush()
except BrokenPipeError:
# Python flushes standard streams on exit; redirect remaining output
# to devnull to avoid another BrokenPipeError at shutdown
devnull = os.open(os.devnull, os.O_WRONLY)
os.dup2(devnull, sys.stdout.fileno())
sys.exit(1) # Python exits with error code 1 on EPIPE
if __name__ == '__main__':
main()
不要将SIGPIPE的处置方式设置为SIG_DFL,以避免BrokenPipeError。这样做还会导致在程序仍在写入时任何套接字 Connecting 断时,程序也会意外退出。