内容简介: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 程序员的信号处理教程
- 音频可视化中的信号处理方案
- 开放下载!《阿里语音与信号处理技术》精选集
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
MD5 加密
MD5 加密工具