On this page
17.4. signal—设置异步事件的处理程序
该模块提供了在 Python 中使用 signal 处理程序的机制。使用 signal 及其处理程序的一些一般规则:
特定 signal 的处理程序(一旦设置)将保持安装状态,直到将其显式重置(Python 会模拟 BSD 样式接口,而不考虑基础实现),但
SIGCHLD
的处理程序除外,该处理程序遵循基础实现。无法暂时性地“阻塞”关键部分的 signal(因为并非所有 Unix 版本都支持此Function)。
尽管就 Python 用户而言,Pythonsignal 处理程序是异步调用的,但它们只能出现在 Python 解释器的“原子”指令之间。这意味着纯粹在 C 语言中执行的长时间计算期间到达的 signal(例如,大文本主体上的正则表达式匹配)可能会延迟任意时间。
当 signal 在 I/O 操作期间到达时,signal 处理程序返回后,I/O 操作可能引发异常。这取决于有关break系统调用的底层 Unix 系统的语义。
由于 Csignal 处理程序始终返回,因此捕获诸如
SIGFPE
或SIGSEGV
之类的同步错误几乎没有意义。Python 默认情况下会安装少量 signal 处理程序:
SIGPIPE
被忽略(因此可以将管道和套接字上的写入错误报告为普通的 Python 异常),而SIGINT
则转换为KeyboardInterrupt异常。所有这些都可以被覆盖。如果在同一程序中同时使用 signal 和线程,则必须格外小心。在同时使用 signal 和线程时要记住的基本内容是:始终在执行主线程中执行signal()操作。任何线程都可以执行alarm(),getsignal(),pause(),setitimer()或getitimer();只有主线程才能设置新的 signal 处理程序,并且主线程将是唯一一个接收 signal 的处理器(这由 Python signal模块强制执行,即使基础线程实现支持将 signal 发送至各个线程)。这意味着 signal 不能用作线程间通信的手段。请改用锁。
signal模块中定义的变量是:
signal.
SIG_DFL
- 这是两个标准 signal 处理选项之一。它只会执行 signal 的默认Function。例如,在大多数系统上,
SIGQUIT
的默认操作是转储核心并退出,而SIGCHLD
的默认操作是简单地忽略它。
- 这是两个标准 signal 处理选项之一。它只会执行 signal 的默认Function。例如,在大多数系统上,
signal.
SIG_IGN
- 这是另一个标准 signal 处理程序,它将简单地忽略给定的 signal。
SIG*
- 所有 signal 编号均以符号方式定义。例如,挂断 signal 定义为
signal.SIGHUP
;变量名与<signal.h>
中的 C 程序中使用的名称相同。signal()
的 Unix 手册页列出了现有的 signal(在某些系统上为* signal(2),在其他系统上,列表位于 signal(7)*中)。请注意,并非所有系统都定义相同的 signal 名称集。此模块仅定义系统定义的名称。
- 所有 signal 编号均以符号方式定义。例如,挂断 signal 定义为
signal.
CTRL_C_EVENT
- 与 Ctrl C 按键事件相对应的 signal。该 signal 只能与os.kill()一起使用。
Availability: Windows.
2.7 版的新Function。
signal.
CTRL_BREAK_EVENT
- 与 Ctrl Break 击键事件相对应的 signal。该 signal 只能与os.kill()一起使用。
Availability: Windows.
2.7 版的新Function。
signal.
NSIG
- 比最高 signal 编号多一。
signal.
ITIMER_REAL
- 实时减少间隔计时器,并在到期时发送
SIGALRM
。
- 实时减少间隔计时器,并在到期时发送
signal.
ITIMER_VIRTUAL
- 仅在进程执行时才减小间隔计时器,并在到期时传递 SIGVTALRM。
signal.
ITIMER_PROF
- 在过程执行时以及系统代表过程执行时,都减小间隔计时器。与 ITIMER_VIRTUAL 结合使用时,该计时器通常用于分析应用程序在用户和内核空间中花费的时间。 SIGPROF 在到期时交付。
signal模块定义了一个 exception:
- exception
signal.
ItimerError
- 引发 signal 来自底层的setitimer()或getitimer()实现。如果将无效的间隔计时器或负时间传递给setitimer(),则会出现此错误。此错误是IOError的子类型。
signal模块定义以下Function:
signal.
alarm
(时间)- 如果* time 不为零,则此函数要求在 time 秒内将
SIGALRM
signal 发送到进程。任何先前计划的警报都会被取消(任何时候都只能计划一个警报)。然后,返回值是在传递任何先前设置的警报之前的秒数。如果 time 为零,则不会安排任何警报,并且任何计划的警报都会被取消。如果返回值为零,则当前未计划任何警报。 (请参见 Unix 手册页 alarm(2)*。)可用性:Unix。
- 如果* time 不为零,则此函数要求在 time 秒内将
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.
pause
( )- 使过程进入休眠状态,直到收到 signal 为止;然后将调用适当的处理程序。不返回任何内容。不在 Windows 上。 (请参阅 Unix 手册页* signal(2)*。)
signal.
setitimer
(* which , seconds * [,* interval *])- 设置由哪个指定的给定间隔计时器(signal.ITIMER_REAL,signal.ITIMER_VIRTUAL或signal.ITIMER_PROF之一)在秒(接受浮点,不同于alarm())之后并在此之后每* interval 秒触发一次。由哪个*指定的间隔计时器可以pass将秒设置为零来清除。
当间隔计时器触发时,signal 将发送到该进程。发送的 signal 取决于所使用的计时器。 signal.ITIMER_REAL将传送SIGALRM
,signal.ITIMER_VIRTUAL发送SIGVTALRM
,而signal.ITIMER_PROF将传送SIGPROF
。
旧值以 Tuples 形式返回:(延迟,间隔)。
trypass无效的间隔计时器将导致ItimerError。可用性:Unix。
2.6 版的新Function。
signal.
getitimer
(* which *)- 返回由* which *指定的给定间隔计时器的当前值。可用性:Unix。
2.6 版的新Function。
signal.
set_wakeup_fd
(* fd *)- 将唤醒 fd 设置为* fd *。接收到 signal 后,会将
'\0'
字节写入 fd。库可以使用它来唤醒轮询或选择调用,从而使 signal 得到充分处理。
- 将唤醒 fd 设置为* fd *。接收到 signal 后,会将
返回旧的唤醒 fd(如果未启用文件 Descriptors 唤醒,则返回-1)。如果* fd 为-1,则禁用文件 Descriptors 唤醒。如果不为-1,则 fd 必须是非阻塞的。在调用 poll 或再次选择之前,库必须从 fd *中删除任何字节。
启用线程后,只能从主线程调用此函数;try从其他线程调用它会引发ValueError异常。
2.6 版的新Function。
signal.
siginterrupt
(* signalnum , flag *)- 更改系统调用重新启动行为:如果* flag 为False,则当 signal signalnum break时,系统调用将重新启动,否则系统调用将被break。不返回任何内容。可用性:Unix(有关更多信息,请参见手册页 siginterrupt(3)*)。
请注意,使用signal()安装 signal 处理程序将pass为给定 signal 隐式调用具有真实* flag *值的siginterrupt()
将重启行为重置为可break的。
2.6 版的新Function。
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
来调用signal()。在任何其他情况下,都将引发ValueError。
17.4.1. Example
这是一个最小的示例程序。它使用alarm()函数来限制 await 打开文件所花费的时间;如果该文件用于可能无法打开的串行设备,这通常会导致os.open()无限期挂起,则这很有用。解决的办法是在打开文件之前设置 5 秒警报。如果操作时间太长,则会发送警报 signal,并且处理程序会引发异常。
import signal, os
def handler(signum, frame):
print 'Signal handler called with signal', signum
raise IOError("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