python模块之signal信号
简介
作用:发送和接收异步系统信号
信号是一个操作系统特性,它提供了一个途径可以通知程序发生了一个事件并异步处理这个事件。信号可以由系统本身生成,也可以从一个进程发送到另一个进程。
由于信号会中断程序的正常控制流,如果在中间接收到信号,有些操作(特别是I/O操作)可能会发生错误。
接收信号
signal.signal(sig,action)
sig为某个信号,action为该信号的处理函数。
例如:
signal.signal(signal.SIGALRM, hanlder) hanlder为信号处理函数
windows下sig信号:
>>> dir(signal) ['CTRL_BREAK_EVENT', 'CTRL_C_EVENT', 'NSIG', 'SIGABRT', 'SIGBREAK', 'SIGFPE', 'SIGILL', 'SIGINT', 'SIGSEGV', 'SIGTERM', 'SIG_DFL', 'SIG_IGN', '__doc__', '__name__', '__package__', 'default_int_handler', 'getsignal', 'set_wakeup_fd', 'signal']
linux下sig信号:
>>> dir(signal) ['ITIMER_PROF', 'ITIMER_REAL', 'ITIMER_VIRTUAL', 'ItimerError', 'NSIG', 'SIGABRT', 'SIGALRM', 'SIGBUS', 'SIGCHLD', 'SIGCLD', 'SIGCONT', 'SIGFPE', 'SIGHUP', 'SIGILL', 'SIGINT', 'SIGIO', 'SIGIOT', 'SIGKILL', 'SIGPIPE', 'SIGPOLL', 'SIGPROF', 'SIGPWR', 'SIGQUIT', 'SIGRTMAX', 'SIGRTMIN', 'SIGSEGV', 'SIGSTOP', 'SIGSYS', 'SIGTERM', 'SIGTRAP', 'SIGTSTP', 'SIGTTIN', 'SIGTTOU', 'SIGURG', 'SIGUSR1', 'SIGUSR2', 'SIGVTALRM', 'SIGWINCH', 'SIGXCPU', 'SIGXFSZ', 'SIG_DFL', 'SIG_IGN', '__doc__', '__name__', '__package__', 'alarm', 'default_int_handler', 'getitimer', 'getsignal', 'pause', 'set_wakeup_fd', 'setitimer', 'siginterrupt', 'signal']
即通过建立一个回调函数来接收信号,这个回调函数称为信号处理函数(signal hanlder),它会在信号出现时调用。
信号处理函数包括信号编号及被信号中断那一时刻的栈帧。
def hanlder(signum, frame): something...
signum即信号编号( 数字),例如:
>>> import signal >>> signal.SIGINT 2
frame为被信号中断那一时刻的栈帧。
接收信号
signal.signal(sig,action)
import signal import os import time def receive_signal(signum, stack): print 'Received:', signum # 注册信号处理程序 signal.signal(signal.SIGUSR1, receive_signal) signal.signal(signal.SIGUSR2, receive_signal) # 打印这个进程的PID方便使用kill传递信号 print 'My PID is:', os.getpid() # 等待信号,有信号发生时则调用信号处理程序 while True: print 'Waiting...' time.sleep(3)
SIGUSR1和SIGUSR2是留给用户使用的信号。windows下无这两个信号。
这个脚本会无限循环,每次暂停3秒钟。有信号到来时,sleep()调用被中断,信号处理程序receive_signal被调用.信号处理程序返回时,循环继续。
发送信号
os.kill(pid, sig):pid为进程号, sig为信号
>>> import os >>> help(os.kill) Help on built-in function kill in module nt: kill(...) kill(pid, sig) Kill a process with a signal. >>>
import os import signal import time def signal_usr1(signum, frame): "Callback invoked when a signal is received" pid = os.getpid() print 'Received USR1 in process %s' % pid print 'Forking...' child_pid = os.fork() if child_pid: print 'PARENT: Pausing before sending signal...' time.sleep(1) print 'PARENT: Signaling %s' % child_pid os.kill(child_pid, signal.SIGUSR1) else: print 'CHILD: Setting up a signal handler' signal.signal(signal.SIGUSR1, signal_usr1) print 'CHILD: Pausing to wait for signal' time.sleep(5)
父进程使用kill()和signal模块向子进程发送信号。在父进程中,使用kill()发送一个USR1信号之前会暂停很短一段时间,这个短暂的暂停使子进程有时间建立信号处理程序。
signal.pause():等待直到接收一个信号
import signal import os import time def do_exit(sig, stack): raise SystemExit('Exiting') # 将SIGINT的默认处理程序替换为SIG_IGN signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGUSR1, do_exit) print 'My PID:', os.getpid() signal.pause()
正常情况下,SIGINT会产生一个KeyboardInterrupt,这个例子将忽略SIGINT,并在发现SIGUSR1时产生一个SystemExit。
signal.alarm(time):如果time是非0,这个函数则响应一个SIGALRM信号并在time秒后发送到该进程。
import signal import time def received_alarm(signum, stack): print 'Alarm:', time.ctime() # Call receive_alarm in seconds signal.signal(signal.SIGALRM, received_alarm) signal.alarm(2) print 'Before:', time.ctime() time.sleep(4) print 'After:', time.ctime()