signal- 为异步事件设置处理程序

该模块提供了在Python中使用信号处理程序的机制。

一般规则

signal.signal()函数允许定义在接收到信号时执行的自定义处理程序。安装了少量默认处理程序:SIGPIPE被忽略(因此管道和套接字上的写入错误可以报告为普通的Python异常),如果父进程没有更改它,SIGINT则会转换为KeyboardInterrupt异常。

一旦设置,特定信号的处理程序将保持安装,直到它被显式重置(Python模拟BSD样式接口而不管底层实现),除了处理程序之外 SIGCHLD,它遵循底层实现。

执行Python信号处理程序

Python信号处理程序不会在低级(C)信号处理程序中执行。相反,低级信号处理程序设置一个标志,告诉 虚拟机稍后执行相应的Python信号处理程序(例如在下一个字节码指令处)。这有后果:

  • 捕获C代码中的无效操作引起的同步错误SIGFPE或 没有意义SIGSEGV。Python将从信号处理程序返回到C代码,这可能会再次引发相同的信号,导致Python显然挂起。从Python 3.3开始,您可以使用该faulthandler模块报告同步错误。
  • 纯粹在C中实现的长时间运行的计算(例如在大量文本上的正则表达式匹配)可以在任意时间内不间断地运行,而不管接收到任何信号。计算完成后将调用Python信号处理程序。

信号和线程

Python信号处理程序总是在主Python线程中执行,即使信号是在另一个线程中接收的。这意味着信号不能用作线程间通信的手段。您可以使用threading模块中的同步原语。

此外,只允许主线程设置新的信号处理程序。

模块内容

在3.5版本中改变了:信号(SIG *),处理器(SIG_DFLSIG_IGN)和sigmask( ,SIG_BLOCKSIG_UNBLOCKSIG_SETMASK下面列出相关的常数,变成 enums。 getsignal()pthread_sigmask()sigpending()和 sigwait()函数返回人类可读的 enums

signal模块中定义的变量是:

signal.SIG_DFL

这是两种标准信号处理选项之一; 它只会执行信号的默认功能。例如,在大多数系统上,默认操作SIGQUIT是转储核心并退出,而默认操作SIGCHLD是简单地忽略它。

signal.SIG_IGN

这是另一个标准信号处理程序,它将简单地忽略给定的信号。

SIG*

所有信号编号都是象征性定义的。例如,挂断信号定义为signal.SIGHUP; 变量名称与C程序中使用的名称相同,如中所示<signal.h>。用于' signal()' 的Unix手册页列出了现有信号(在某些系统上这是 信号(2),在其他系统上列出信号(7))。请注意,并非所有系统都定义了相同的信号名称集; 只有系统定义的名称才由此模块定义。

signal.CTRL_C_EVENT

对应于Ctrl+C击键事件的信号。此信号只能用于os.kill()

可用性:Windows。

版本3.2中的新功能。

signal.CTRL_BREAK_EVENT

对应于Ctrl+Break击键事件的信号。此信号只能用于os.kill()

可用性:Windows。

版本3.2中的新功能。

signal.NSIG

比最高信号数多一个。

signal.ITIMER_REAL

实时递减间隔计时器,并SIGALRM在到期时递送。

signal.ITIMER_VIRTUAL

仅在进程执行时递减间隔计时器,并在到期时递送SIGVTALRM。

signal.ITIMER_PROF

在进程执行时以及系统代表进程执行时,都会减少间隔计时器。与ITIMER_VIRTUAL结合使用,此计时器通常用于分析应用程序在用户和内核空间中花费的时间。SIGPROF在到期时交付。

signal.SIG_BLOCK

how参数的可能值,用于pthread_sigmask() 指示要阻止信号。

版本3.3中的新功能。

signal.SIG_UNBLOCK

how参数的可能值,用于pthread_sigmask() 指示要解除阻塞信号。

版本3.3中的新功能。

signal.SIG_SETMASK

how参数的可能值,用于pthread_sigmask() 指示要替换信号掩码。

版本3.3中的新功能。

signal模块定义了一个例外:

异常signal.ItimerError

提升以表示来自底层setitimer()或 getitimer()实现的错误。如果传递无效的间隔计时器或负时间,则会出现此错误setitimer()。此错误是的子类型OSError

版本3.3中的新功能:此错误曾经是子类型IOError,现在是别名OSError

signal模块定义了以下功能:

signal.alarm时间

如果时间不为零,则此函数请求SIGALRM时间秒内将信号发送到进程。取消任何先前安排的警报(任何时候只能安排一个警报)。然后返回的值是任何先前设置的警报发送之前的秒数。如果时间为零,则不会安排任何警报,并且会取消任何计划的警报。如果返回值为零,则当前没有安排警报。(参见Unix手册页报警(2)。)

可用性:Unix。

signal.getsignalsignalnum 

返回信号signalnum的当前信号处理程序。返回的值可以是可调用的Python对象,也可以是特殊值之一signal.SIG_IGNsignal.SIG_DFL或者None。这里 signal.SIG_IGN意味着信号先前被忽略, signal.SIG_DFL意味着处理信号的默认方式以前在使用,None意味着之前的信号处理程序没有从Python安装。

signal.pause()

导致进程进入睡眠状态,直到收到信号为止; 然后将调用适当的处理程序。什么都不返回 不在Windows上。(参见Unix手册页 信号(2)。)

又见sigwait()sigwaitinfo()sigtimedwait()和 sigpending()

signal.pthread_killthread_idsignalnum 

将信号signalnum发送到线程thread_id,与调用者处于同一进程中的另一个线程。目标线程可以执行任何代码(Python或不)。但是,如果目标线程正在执行Python解释器,则Python信号处理程序将由主线程执行。因此,向特定Python线程发送信号的唯一方法是强制正在运行的系统调用失败InterruptedError

使用threading.get_ident()或对象的ident 属性threading.Thread来获取thread_id的合适值。

如果signalnum为0,则不发送信号,但仍然执行错误检查; 这可用于检查目标线程是否仍在运行。

可用性:Unix(有关详细信息,请参见手册页 pthread_kill(3))。

另见os.kill()

版本3.3中的新功能。

signal.pthread_sigmask怎么样面具

获取和/或更改调用线程的信号掩码。信号掩码是一组信号,其传送当前被呼叫者阻止。将旧信号掩码作为一组信号返回。

调用的行为是依赖于价值如何,如下所示。

  • SIG_BLOCK:阻塞信号集是当前集和掩码参数的并集。
  • SIG_UNBLOCK掩码中的信号从当前阻塞信号集中删除。允许尝试解锁未被阻塞的信号。
  • SIG_SETMASK:阻塞信号集设置为掩码 参数。

mask是一组信号编号(例如{ signal.SIGINT, signal.SIGTERM})。使用一个完整的屏蔽在内的所有信号。range(1, signal.NSIG)

例如,读取调用线程的信号掩码。signal.pthread_sigmask(signal.SIG_BLOCK, [])

可用性:Unix。有关详细信息,请参见手册页 sigprocmask(3)和 pthread_sigmask(3)

另见pause()sigpending()sigwait()

版本3.3中的新功能。

signal.setitimer其中间隔= 0.0 

给定的间隔计时器集(之一signal.ITIMER_REAL, signal.ITIMER_VIRTUALsignal.ITIMER_PROF通过指定),其之后触发(浮子被接受时,从不同的 alarm()),并且每一个后间隔秒(如果间隔 是非零)。通过指定的时间间隔定时器,其可以通过设置被清除到零。

当间隔计时器触发时,会向进程发送一个信号。发送的信号取决于使用的定时器; signal.ITIMER_REAL将交付SIGALRM, signal.ITIMER_VIRTUAL发送SIGVTALRMsignal.ITIMER_PROF交付SIGPROF

旧值作为元组返回:(延迟,间隔)。

尝试传递无效的间隔计时器将导致 ItimerError

可用性:Unix。

signal.getitimer哪个

返回由指定的给定的时间间隔定时器的当前值,其

可用性:Unix。

signal.set_wakeup_fdfd*warn_on_full_buffer = True 

将唤醒文件描述符设置为fd。当接收到信号时,信号编号​​作为单个字节写入fd。库可以使用它来唤醒轮询或选择呼叫,从而允许信号被完全处理。

返回旧的唤醒fd(如果未启用文件描述符唤醒,则返回-1)。如果fd为-1,则禁用文件描述符唤醒。如果不是-1,则fd必须是非阻塞的。在调用poll或再次选择之前,由库来删除fd中的任何字节。

启用线程时,只能从主线程调用此函数; 试图从其他线程调用它将导致引发ValueError 异常。

有两种常用方法可以使用此功能。在这两种方法中,您使用fd在信号到达时唤醒,但随后它们确定哪些信号或哪些信号到达时会有所不同。

在第一种方法中,我们从fd的缓冲区中读取数据,字节值为您提供信号编号。这很简单,但在极少数情况下它会遇到问题:通常fd将具有有限的缓冲区空间,并且如果太多信号到达太快,则缓冲区可能变满,并且一些信号可能丢失。如果你使用这种方法,那么你应该设置 warn_on_full_buffer=True,这至少会在信号丢失时将警告打印到stderr。

在第二种方法中,我们将唤醒fd 用于唤醒,并忽略实际的字节值。在这种情况下,我们关心的是fd的缓冲区是空的还是非空的; 完整缓冲区根本不表示存在问题。如果您使用此方法,则应进行设置warn_on_full_buffer=False,以便您的用户不会被虚假警告消息混淆。

在3.5版中更改:在Windows上,该功能现在还支持套接字句柄。

版本3.7中已更改:已添加warn_on_full_buffer参数。

signal.siginterruptsignalnumflag 

更改系统调用重启行为:如果标志False,则系统调用将在信号signalnum中断时重新启动,否则系统调用将被中断。什么都不返回

可用性:Unix( 有关详细信息,请参见手册页 siginterrupt(3))。

请注意,安装信号处理程序signal()将通过siginterrupt()使用给定信号的true 标志值隐式调用来将重启行为重置为可中断 。

signal.signalsignalnumhandler 

将信号signalnum的处理程序设置为函数处理程序。 handler可以是一个可调用的Python对象,它带有两个参数(见下文),或者一个特殊值signal.SIG_IGN或者signal.SIG_DFL。将返回先前的信号处理程序(参见getsignal() 上面的描述)。(参见Unix手册页信号(2)。)

启用线程时,只能从主线程调用此函数; 试图从其他线程调用它将导致引发ValueError 异常。

处理程序被调用时两个参数:信号数和当前堆栈帧(None或一帧的对象;对帧的对象的描述,请参见在类型层次描述或看到在属性描述inspect模块)。

在Windows中,signal()只能叫SIGABRT, SIGFPESIGILLSIGINTSIGSEGV, SIGTERM,或SIGBREAKValueError在任何其他情况下都会提出A. 请注意,并非所有系统都定义了相同的信号名称集; AttributeError如果信号名称未定义为SIG*模块级别常量, 则将引发a 。

signal.sigpending()

检查待传递到调用线程的信号集(即,阻塞时已经引发的信号)。返回待处理信号的集合。

可用性:Unix(有关详细信息,请参见手册页 sigpending(2))。

另见pause()pthread_sigmask()sigwait()

版本3.3中的新功能。

signal.sigwaitsigset 

暂停执行调用线程,直到传递信号集sigset中指定的信号之一。该函数接受信号(将其从待处理的信号列表中删除),并返回信号编号。

可用性:Unix(有关详细信息,请参见手册页 sigwait(3))。

又见pause()pthread_sigmask()sigpending(), sigwaitinfo()sigtimedwait()

版本3.3中的新功能。

signal.sigwaitinfosigset 

暂停执行调用线程,直到传递信号集sigset中指定的信号之一。该函数接受信号并将其从待处理的信号列表中删除。如果sigset中的一个信号已经为调用线程挂起,则该函数将立即返回有关该信号的信息。不为传递的信号调用信号处理程序。如果函数InterruptedError被不在sigset中的信号中断, 该函数会引发该函数 。

返回值是表示包含在该数据对象 siginfo_t的结构,即:si_signosi_code, si_errnosi_pidsi_uidsi_status, si_band

可用性:Unix(有关详细信息,请参见手册页 sigwaitinfo(2))。

另见pause()sigwait()sigtimedwait()

版本3.3中的新功能。

在版本3.5中更改:如果由不在sigset中 的信号中断并且信号处理程序不引发异常,则现在重试该函数(请参阅PEP 475的理由)。

signal.sigtimedwaitsigsettimeout 

喜欢sigwaitinfo(),但需要额外的超时参数来指定超时。如果指定超时0,则执行轮询。None如果发生超时则返回。

可用性:Unix(有关详细信息,请参见手册页 sigtimedwait(2))。

另见pause()sigwait()sigwaitinfo()

版本3.3中的新功能。

在版本3.5中更改:如果由不在sigset中的信号中断并且信号处理程序不引发异常,则现在使用重新计算的超时重试该函数(请参阅PEP 475的理由)。

示例

这是一个最小的示例程序。它使用该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

关于SIGPIPE的注意事项

将程序输出到head(1)等工具将导致在SIGPIPE标准输出的接收器提前关闭时将信号发送到您的进程。这会导致例外情况。要处理这种情况,请包装入口点以捕获此异常,如下所示: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。这样做会导致程序在程序仍在写入时中断任何套接字连接时意外退出。

转载于:https://my.oschina.net/u/3612528/blog/3050968

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值