Python信号处理

栏目: Python · 发布时间: 7年前

内容简介: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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Open Data Structures

Open Data Structures

Pat Morin / AU Press / 2013-6 / USD 29.66

Offered as an introduction to the field of data structures and algorithms, Open Data Structures covers the implementation and analysis of data structures for sequences (lists), queues, priority queues......一起来看看 《Open Data Structures》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器