python / 2.7.15 / all / library-signal.html

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 处理程序始终返回,因此捕获诸如SIGFPESIGSEGV之类的同步错误几乎没有意义。

  • 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. SIG_IGN

    • 这是另一个标准 signal 处理程序,它将简单地忽略给定的 signal。
  • SIG*

    • 所有 signal 编号均以符号方式定义。例如,挂断 signal 定义为signal.SIGHUP;变量名与<signal.h>中的 C 程序中使用的名称相同。 signal()的 Unix 手册页列出了现有的 signal(在某些系统上为* signal(2),在其他系统上,列表位于 signal(7)*中)。请注意,并非所有系统都定义相同的 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模块定义以下Function:

  • signal. alarm(时间)

    • 如果* time 不为零,则此函数要求在 time 秒内将SIGALRMsignal 发送到进程。任何先前计划的警报都会被取消(任何时候都只能计划一个警报)。然后,返回值是在传递任何先前设置的警报之前的秒数。如果 time 为零,则不会安排任何警报,并且任何计划的警报都会被取消。如果返回值为零,则当前未计划任何警报。 (请参见 Unix 手册页 alarm(2)*。)可用性:Unix。
  • signal. getsignal(* signalnum *)

    • 返回 signal* signalnum *的当前 signal 处理程序。返回的值可以是可调用的 Python 对象,也可以是特殊值signal.SIG_IGNsignal.SIG_DFLNone之一。在这里,signal.SIG_IGN表示先前已忽略 signal,signal.SIG_DFL表示先前已使用默认的 signal 处理方式,None表示未从 Python 安装以前的 signal 处理程序。
  • signal. pause ( )

    • 使过程进入休眠状态,直到收到 signal 为止;然后将调用适当的处理程序。不返回任何内容。不在 Windows 上。 (请参阅 Unix 手册页* signal(2)*。)
  • signal. setitimer(* which seconds * [,* interval *])

当间隔计时器触发时,signal 将发送到该进程。发送的 signal 取决于所使用的计时器。 signal.ITIMER_REAL将传送SIGALRMsignal.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(如果未启用文件 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_IGNsignal.SIG_DFL之一的可调用 Python 对象。将返回之前的 signal 处理程序(请参见上面的getsignal()的描述)。 (请参阅 Unix 手册页 signal(2)。)

启用线程后,只能从主线程调用此函数;try从其他线程调用它会引发ValueError异常。

使用两个参数调用* handler *:signal 编号和当前堆栈帧(None或帧对象;有关帧对象的说明,请参见类型层次结构中的描述或在inspect模块中查看属性说明)。

在 Windows 上,只能使用SIGABRTSIGFPESIGILLSIGINTSIGSEGVSIGTERM来调用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