18.8. signal
- 设置异步事件处理程序¶
此模块提供了在Python中使用信号处理程序的机制。
18.8.1. General rules¶
signal.signal()
函数允许定义在接收到信号时执行的自定义处理程序。安装了少量默认处理程序:SIGPIPE
被忽略(因此管道和套接字上的写入错误可以报告为普通Python异常),SIGINT
被转换为KeyboardInterrupt
异常。
特定信号的处理程序一旦设置,将保持安装状态,直到显式复位(不管底层实现如何,Python都会模拟BSD样式接口),除了SIGCHLD
的处理程序底层实现。
18.8.1.1. Execution of Python signal handlers¶
Python信号处理程序不会在低级(C)信号处理程序内部执行。相反,低级信号处理程序在稍后的点(例如在下一个bytecode指令处)设置告知virtual machine执行相应的Python信号处理程序的标志。这有后果:
- 捕获由C代码中的无效操作导致的类似于
SIGFPE
或SIGSEGV
的同步错误没有什么意义。Python将从信号处理程序返回到C代码,这可能再次引发相同的信号,导致Python显然挂起。从Python 3.3开始,您可以使用faulthandler
模块报告同步错误。 - 完全在C中执行的长时间运行的计算(例如对大量文本的正则表达式匹配)可以不间断地运行任意时间量,而不管接收到任何信号。Python信号处理程序将在计算完成时调用。
18.8.2. Module contents¶
在版本3.5中更改了信号(SIG *),处理程序(SIG_DFL
,SIG_IGN
)和sigmask(SIG_BLOCK
SIG_UNBLOCK
,SIG_SETMASK
)相关常数变成enums
。getsignal()
, pthread_sigmask()
, sigpending()
and sigwait()
functions return human-readable enums
.
在signal
模块中定义的变量是:
-
signal.
SIG_DFL
¶ 这是两个标准信号处理选项之一;它将简单地执行信号的默认功能。例如,在大多数系统上,
SIGQUIT
的默认操作是转储核心和退出,而SIGCHLD
的默认操作是简单地忽略它。
-
signal.
SIG_IGN
¶ 这是另一个标准信号处理程序,它将简单地忽略给定的信号。
SIG *
所有信号编号都用符号定义。例如,挂起信号定义为
signal.SIGHUP
;变量名称与C程序中使用的名称相同,如<signal.h>
中所述。The Unix man page for ‘signal()
‘ lists the existing signals (on some systems this is signal(2), on others the list is in signal(7)). 请注意,并非所有系统都定义相同的信号名称集;只有由系统定义的那些名称由此模块定义。
-
signal.
NSIG
¶ 一个多于最高信号数的数。
-
signal.
ITIMER_REAL
¶ 实时递减间隔定时器,并在到期时递送
SIGALRM
。
-
signal.
ITIMER_VIRTUAL
¶ 仅在进程正在执行时减少间隔定时器,并在到期时传递SIGVTALRM。
-
signal.
ITIMER_PROF
¶ 递减间隔定时器,当进程执行时和系统代表进程执行时。与ITIMER_VIRTUAL相耦合,此定时器通常用于配置应用程序在用户和内核空间中花费的时间。SIGPROF在到期时交付。
-
signal.
SIG_BLOCK
¶ 如何参数到
pthread_sigmask()
的可能值,表示要阻止信号。版本3.3中的新功能。
-
signal.
SIG_UNBLOCK
¶ 如何参数到
pthread_sigmask()
的可能值,表示要解除阻塞信号。版本3.3中的新功能。
-
signal.
SIG_SETMASK
¶ 如何参数到
pthread_sigmask()
的可能值,表示要替换信号掩码。版本3.3中的新功能。
signal
模块定义了一个例外:
- exception
signal.
ItimerError
¶ 引发来自底层
setitimer()
或getitimer()
实现的错误信号。如果将无效的间隔定时器或负时间传递到setitimer()
,则会发生此错误。此错误是OSError
的子类型。
signal
模块定义以下功能:
-
signal.
alarm
(time)¶ 如果时间不为零,则此功能请求在时间秒内将
SIGALRM
信号发送到过程。任何先前安排的警报被取消(只能在任何时间安排一个警报)。返回的值是之前设置的任何警报发送之前的秒数。如果时间为零,则不计划报警,并取消任何预设报警。如果返回值为零,则当前未调度报警。(参见Unix手册页alarm(2)。)可用性:Unix。
-
signal.
getsignal
(signalnum)¶ 返回信号signalnum的当前信号处理程序。返回的值可以是可调用的Python对象或特殊值
signal.SIG_IGN
,signal.SIG_DFL
或None
之一。这里,signal.SIG_IGN
意味着信号先前被忽略,signal.SIG_DFL
意味着处理信号的默认方式是先前使用的,并且None
-
signal.
pause
()¶ 使该过程睡眠直到接收到信号;那么将调用适当的处理程序。不返回任何内容。不在Windows上。(请参见Unix手册页信号(2)。)
-
signal.
pthread_kill
(thread_id, signalnum)¶ 将信号signalnum发送到线程thread_id,这是与调用者相同的进程中的另一个线程。目标线程可以执行任何代码(Python或不是)。但是,如果目标线程正在执行Python解释器,则Python信号处理程序将由主线程执行executed by the main thread因此,向特定Python线程发送信号的唯一一点是强制运行系统调用失败,并显示
InterruptedError
。使用
threading.get_ident()
或threading.Thread
对象的ident
属性为thread_id 。如果signalnum为0,则不发送信号,但仍然执行错误检查;这可以用于检查目标线程是否仍在运行。
可用性:Unix(有关详细信息,请参见手册页pthread_kill(3))。
另请参见
os.kill()
。版本3.3中的新功能。
-
signal.
pthread_sigmask
(how, mask)¶ 获取和/或更改调用线程的信号掩码。信号掩码是当前为呼叫者阻止其传递的一组信号。将旧的信号掩码作为一组信号返回。
调用的行为取决于如何的值,如下所示。
SIG_BLOCK
:阻塞信号集合是当前集合的共用体和掩码参数。SIG_UNBLOCK
:掩码中的信号从当前阻塞信号集中删除。允许尝试解除未阻塞的信号。SIG_SETMASK
:阻塞信号集设置为掩码参数。
掩码是一组信号号码(例如,{
signal.SIGINT
,signal.SIGTERM
})。使用范围(1, signal.NSIG)
获取包含所有信号的完整掩码。例如,
signal.pthread_sigmask(signal.SIG_BLOCK, [])
读取调用线程的信号掩码。可用性:Unix。有关更多信息,请参阅手册页sigprocmask(3)和pthread_sigmask(3)
另请参见
pause()
,sigpending()
和sigwait()
。版本3.3中的新功能。
-
signal.
setitimer
(which, seconds[, interval])¶ 设置由指定的给定间隔定时器(
signal.ITIMER_REAL
,signal.ITIMER_VIRTUAL
或signal.ITIMER_PROF
在秒(接受浮动,不同于alarm()
)之后,每隔间隔由指定的间隔定时器可以通过将秒设置为零来清除。当间隔定时器触发时,向处理发送信号。The signal sent is dependent on the timer being used;
signal.ITIMER_REAL
will deliverSIGALRM
,signal.ITIMER_VIRTUAL
sendsSIGVTALRM
, andsignal.ITIMER_PROF
will deliverSIGPROF
.旧值作为元组返回:(delay,interval)。
尝试传递无效间隔定时器将导致
ItimerError
。可用性:Unix。
-
signal.
getitimer
(which)¶ 返回由指定的给定间隔定时器的当前值,其中。可用性:Unix。
-
signal.
set_wakeup_fd
(fd)¶ 将唤醒文件描述器设置为fd。当接收到信号时,信号号作为单字节写入fd。这可以由库用来唤醒轮询或选择呼叫,从而允许完全处理信号。
返回旧的唤醒fd。fd必须是非阻塞的。在调用poll之前由库删除任何字节或再次选择。
使用例如
struct.unpack('%uB' % len(data), data)
来解码信号编号列表。当启用线程时,此函数只能从主线程调用;尝试从其他线程调用它将导致引发
ValueError
异常。在3.5版本中更改:在Windows上,此函数现在还支持套接字句柄。
-
signal.
siginterrupt
(signalnum, flag)¶ 更改系统呼叫重新启动行为:如果标志为
False
,系统呼叫将在由信号signalnum中断时重新启动,否则系统呼叫将中断。不返回任何内容。可用性:Unix(有关详细信息,请参见手册页siginterrupt(3))。请注意,使用
signal()
安装信号处理程序将通过隐式调用siginterrupt()
将真实的标志给定的信号。
-
signal.
signal
(signalnum, handler)¶ 将信号signalnum的处理程序设置为处理程序。处理程序可以是具有两个参数(见下文)或特殊值
signal.SIG_IGN
或signal.SIG_DFL
的可调用Python对象。将返回上一个信号处理程序(请参阅上面的getsignal()
的描述)。(请参见Unix手册页信号(2)。)当启用线程时,此函数只能从主线程调用;尝试从其他线程调用它将导致引发
ValueError
异常。使用两个参数调用处理程序:信号编号和当前堆栈帧(
None
或帧对象;有关帧对象的描述,请参阅description in the type hierarchy中,或查看inspect
模块中的属性说明)。On Windows,
signal()
can only be called withSIGABRT
,SIGFPE
,SIGILL
,SIGINT
,SIGSEGV
, orSIGTERM
. 在任何其他情况下,将引发ValueError
。请注意,并非所有系统都定义相同的信号名称集;如果信号名称未定义为SIG*
模块级常数,则会引发AttributeError
。
-
signal.
sigpending
()¶ 检查等待传递到调用线程的信号集合(即,在阻塞时已经产生的信号)。返回待处理信号的集合。
可用性:Unix(有关详细信息,请参见手册页sigpending(2))。
另请参见
pause()
,pthread_sigmask()
和sigwait()
。版本3.3中的新功能。
-
signal.
sigwait
(sigset)¶ 挂起调用线程的执行,直到发送信号集sigset中指定的信号之一。该函数接受信号(将其从待处理的信号列表中删除),并返回信号编号。
可用性:Unix(有关详细信息,请参见手册页sigwait(3))。
另请参见
pause()
,pthread_sigmask()
,sigpending()
,sigwaitinfo()
和sigtimedwait()
。版本3.3中的新功能。
-
signal.
sigwaitinfo
(sigset)¶ 挂起调用线程的执行,直到发送信号集sigset中指定的信号之一。该函数接受信号并将其从待处理的信号列表中删除。如果sigset中的信号之一已经等待调用线程,则函数将立即返回有关该信号的信息。对于传递的信号,不调用信号处理程序。如果函数被不在sigset中的信号中断,则函数引发
InterruptedError
。返回值是表示包含在
siginfo_t
结构中的数据的对象,即:si_signo
,si_code
,si_errno
,si_pid
,si_uid
,si_status
,si_band
。可用性:Unix(有关详细信息,请参见手册页sigwaitinfo(2))。
另请参见
pause()
,sigwait()
和sigtimedwait()
。版本3.3中的新功能。
在版本3.5中更改:如果信号不在sigset中,信号处理程序不引发异常,则此函数现在重试(请参阅 PEP 475的理由)。
-
signal.
sigtimedwait
(sigset, timeout)¶ 像
sigwaitinfo()
,但是需要一个额外的超时参数指定超时。如果超时被指定为0
,则执行轮询。如果发生超时,则返回None
。可用性:Unix(有关详细信息,请参见手册页sigtimedwait(2))。
另请参见
pause()
,sigwait()
和sigwaitinfo()
。版本3.3中的新功能。
在版本3.5中更改:如果被不在sigset中的信号中断,并且信号处理程序未引发,则重新计算的超时异常(有关理由,请参见 PEP 475)。
18.8.3. Example¶
这里是一个最小的示例程序。它使用alarm()
函数来限制等待打开文件所花费的时间;如果文件用于可能无法打开的串行设备,这通常会导致os.open()
无限期挂起,这是非常有用的。解决方法是在打开文件之前设置5秒报警;如果操作花费太长时间,将发送报警信号,并且处理程序引发异常。
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