内容简介:Python信号处理
目录
Python标准库的signal模块提供了信号处理的功能。
本文是在 Python 2.7.5下测试通过的。Python3X对signal模块进行了增强,本文不做讨论。
signal.signal()
函数用于给信号自定义处理函数。当进程收到信号时,就会执行相应的信号处理函数。
下面看一个例子:
[root@iZj6chejzrsqpclb7miryaZ ~]# cat t.py # coding: utf8 import time import os import threading import signal IS_QUIT = False <strong># 信号处理函数的第一个参数是信号,第二个参数是当前的桢对象</strong> def on_quit(signal_number, frame_object): print "thread: %s received signal: %d" % ( threading.current_thread(), signal_number) global IS_QUIT IS_QUIT = True if __name__ == "__main__": signal.signal(signal.SIGUSR1, on_quit) print "pid is: %d" % os.getpid() while not IS_QUIT: time.sleep(0.1) [root@iZj6chejzrsqpclb7miryaZ ~]# python t.py pid is: <em>7898</em>
打开另外一个窗口,执行:
kill -USR1 <em>7898</em>
回到第一个窗口,会看到,类似下面的信息:
thread: <_MainThread(MainThread, started 140363276531520)> received signal: 10
并且程序从循环中退出了。
使用信号时,需要注意的事项[]
- 并非所有的信号都能被程序捕获,比如SIGKILL就不能被程序捕获,SIGINT可以被应用程序捕获
- 不同的操作系统平台,支持的信号是不同的。比如 Linux 支持SIGUSR1,但是Windows不支持
-
每个信号都有两种表述形式:宏名 和 数字,它们是等价的。在Linux下,可以通过
kill -l
列出所有的信号 -
在Linux下,可以通过
kill -<宏名/数字> <pid>
命令发送信号;在Python中,可以通过os.kill(<pid>, <sig>)
函数发送信号 - 在Python中,只有主线程能够注册信号处理函数,也只有主线程能够处理信号!!!
- 每个信号都有自己独特的用途,比如,按下ctrl + c,会向程序发送SIGINT信号;Linux关机的时候,会向所有的进程先发送SIGTERM信号,过一段时间,再发送SIGKILL信号,强制杀死进程;子进程退出的时候,操作系统会向其父进程发送SIGCHLD信号
- 信号处理是异步的
1,singal.pause()[]
该函数会导致进程休眠,一直到收到一个信号。同时,相应的信号处理函数也会被执行。(Windows不支持)
[root@iZj6chejzrsqpclb7miryaZ ~]# cat t.py import signal import os print "pid is: %d" % os.getpid() signal.signal(signal.SIGINT, lambda *a, **kw: None) signal.pause() [root@iZj6chejzrsqpclb7miryaZ ~]# python t.py pid is: 7944 ^C[root@iZj6chejzrsqpclb7miryaZ ~]#
2,signal.set_wakeup_fd( fd )[]
将wakeup描述符设置为 fd 。当收到信号时,'\0'这个字节会被写到 fd 。该函数通常用于唤醒poll或select调用。同时, 需要信号被信号处理函数处理。
该函数会返回之前设置的wakeup描述符,如果原来没有设置过wakeup描述符,那么返回-1。如果将fd设置为-1,那么会关闭wakeup功能;否则,fd必须是非阻塞的。使用signal.set_wakeup_fd()函数的库,在再次调用poll或select之前,应该读尽fd的缓冲区。
在非主线程上调用该函数,会引发ValueError异常。
[root@iZj6chejzrsqpclb7miryaZ ~]# cat t.py # coding: utf8 import signal import os import struct import socket print "pid is: %d" % os.getpid() class Waker: def __init__(self): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定0端口 - 操作系统会随机分配一个空闲端口 sock.bind(("127.0.0.1", 0)) host, port = sock.getsockname() sock.listen(1) self.writer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.writer.connect((host, port)) self.writer.setblocking(False) self.reader, _ = sock.accept() self.reader.setblocking(False) sock.close() def consume(self): try: while True: data = self.reader.recv(1024) if not data: break print repr(data) except (IOError, socket.error) as ex: pass def get_wakeup_fd(self): return self.writer.fileno() waker = Waker() def on_sig_int(sn, fo): print "on_sig_int" waker.consume() signal.signal(signal.SIGINT, on_sig_int) signal.set_wakeup_fd(waker.get_wakeup_fd()) while True: import time time.sleep(0.2) [root@iZj6chejzrsqpclb7miryaZ ~]# python t.py pid is: 9148 ^Con_sig_int '\x00' ^Z [1]+ 已停止 python t.py [root@iZj6chejzrsqpclb7miryaZ ~]# kill -9 %1 [1]+ 已停止 python t.py
3,定时器之:signal.alarm( time )[]
如果 time 非0,那么该函数会在 time 秒之后,向进程发送SIGALRM信号,之前设置的alarm信号会被取消;如果 time 为0,则只是简单的取消之前设置的alarm信号。该函数返回之前设置的alarm信号距离投递还有多少秒。 time 必须是整数。
[root@iZj6chejzrsqpclb7miryaZ ~]# cat t.py import signal import time def on_sig_alarm(sn, fo): print "receive alarm after %s second(s)" % (time.time() - start_time) signal.signal(signal.SIGALRM, on_sig_alarm) signal.alarm(3) time.sleep(1) print signal.alarm(1) start_time = time.time() time.sleep(10) [root@iZj6chejzrsqpclb7miryaZ ~]# python t.py 2 receive alarm after 0.999886989594 second(s)
4,定时器之:signal.setitimer( which , seconds , interval )[]
which 用来指定定时器的类型:
-
signal.ITIMER_REAL
:真实时间定时器,和alarm相同,会发送SIGALRM信号 -
signal.ITIMER_VIRTUAL
:用户态时间定时器,会发送SIGVTALRM信号 -
signal.ITIMER_PROF
:用户态+内核态时间定时器,会发送SIGPROF信号
seconds :表示在 seconds 秒后发送第一个信号
interval :表示之后每 interval 秒发送一个信号
当 seconds 等于0时,会取消之前设置的 which 类型的定时器。
该函数返回,之前设置的 which 类型的定时器,距离投递还有多少秒 以及 该类型的定时器的 interval 。
[root@iZj6chejzrsqpclb7miryaZ ~]# cat t.py import os import signal def on_sig_alrm(sn, fo): print "on_sig_alrm" print "do something here" def handle_signal(): signal.signal(signal.SIGALRM, on_sig_alrm) signal.setitimer(signal.ITIMER_REAL, 1, 1) if __name__ == "__main__": print "pid: %d" % os.getpid() handle_signal() import time while True: time.sleep(0.2) [root@iZj6chejzrsqpclb7miryaZ ~]# python t.py pid: 9342 on_sig_alrm do something here on_sig_alrm do something here ^CTraceback (most recent call last): File "t.py", line 18, in <module> time.sleep(0.2) KeyboardInterrupt </module>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- xenomai内核解析之信号signal(二)---xenomai信号处理机制
- Linux信号处理机制
- Python内核阅读(二十五):信号处理机制
- 写给 PHP 程序员的信号处理教程
- 音频可视化中的信号处理方案
- 开放下载!《阿里语音与信号处理技术》精选集
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。