信号:进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号。操作系统规定了进程收到信号以后的默认行为,但是,我们可以通过绑定信号处理函数来修改进程收到信号以后的行为,有两个信号是不可更改的SIGTOP和SIGKILL。
发送信号一般有两种原因:
1(被动式) 内核检测到一个系统事件.例如子进程退出会像父进程发送SIGCHLD信号.键盘按下control+c会发送SIGINT信号
2(主动式) 通过系统调用kill来向指定进程发送信号
接收信号的进程对不同的信号有三种处理方法:
- 指定处理函数
- 忽略
- 根据系统默认值处理, 大部分信号的默认处理是终止进程
设置信号处理函数
signal.signal(signum, handler)
功能:按照handler制定的信号处理方案处理函数
参数:
signum:拟需处理的信号,处理信号只针对这一种信号起作用sig
hander:信号处理方案
在信号基础里提到,进程可以无视信号、可采取默认操作、还可自定义操作;当handler为下列函数时,将有如下操作:
SIG_IGN:信号被无视(ignore)或忽略
SIG_DFL:进程采用默认(default)行为处理
自定义函数:handler为一个函数名时,进程采用自定义函数处理
SIGSTOP SIGKILL不能处理,只能采用
关于该方法有两个注意点:
1)该方法是有返回值的,其将返回之前原有的信号处理函数;
2)该方法仅能在主线程中注册信号处理器,若在子线程中注册,将引发ValueError异常。
handle的基本定义格式如下:
def handle(signum,frame):
pass
其中signum为待注册的信号量,frame为当前程序运行堆栈frame
计时器alarm
在C语言中有个setitimer函数,函数setitimer可以提供三种定时器,它们相互独立,任意一个定时完成都将发送定时信号到进程,并且自动重新计时。参数which确定了定时器的类型:
ITIMER_REAL 定时真实时间,与alarm类型相同。 SIGALRM
ITIMER_VIRT 定时进程在用户态下的实际执行时间。 SIGVTALRM
ITIMER_PROF 定时进程在用户态和核心态下的实际执行时间。 SIGPROF
这三种定时器定时完成时给进程发送的信号各不相同,其中ITIMER_REAL类定时器发送SIGALRM信号,ITIMER_VIRT类定时器发送SIGVTALRM信号,ITIMER_REAL类定时器发送SIGPROF信号。
函数alarm本质上设置的是低精确、非重载的ITIMER_REAL类定时器,它只能精确到秒,并且每次设置只能产生一次定时。函数setitimer设置的定时器则不同,它们不但可以计时到微妙(理论上),还能自动循环定时。在一个Unix进程中,不能同时使用alarm和ITIMER_REAL类定时器
signal.alarm(time)
调用后过time秒发出一个ALRM信号
若注册了SIGALRM信号的处理函数,则相关handle会被调用。当time为0时,取消注册ALRM信号处理函数。
getsignal函数
signal.getsignal(signalnum)
返回目前程序注册signalnum信号量的处理函数
返回值可能是Python函数,signal.SIG_DFL,signal.SIG_IGN或None。
pause函数
signal.alarm(time)
使程序进入睡眠,直到程序接收到某个信号量
setitimer函数
signal.setitimer(which, seconds[, interval])
设置一个时间计时器,在经过seconds时间后触发which(signal.ITIMER_REAL, signal.ITIMER_VIRTUAL or signal.ITIMER_PROF),并且以后每隔interval时间进行轮训。interval设置为0表示清除which。
getitimer函数
signal.getitimer(which)
返回一个当前which指定的interval时间。
set_wakeup_fd函数
signal.set_wakeup_fd(fd)
设置唤醒一个fd,当收到相关信号后
siginterrupt函数
signal.siginterrupt(signalnum, flag)
改变默认的系统调用行为,如果flag设置为False,当收到中断信号后,系统调用会被重新启动。
如何发送信号
1)如果在命令行中,可以用kill命令向对应进程发送信号,或者使用快捷键(如「CTRL-C」,Python程序会收到SIGINT信号),具体可参考上篇博客。
2)如果在Python程序中,则可借助Python的os模块:
os.kill(pid, signal):向进程号pid对应进程发送signal信号量
而进程号的获取,则可以借助下面两个方法:
os.getpid():获取程序的进程ID
os.getppid():获取程序的父进程ID
异常
signal.ItimerError
获取在执行setitimer()和getitimer()时的异常错误。
版权归原作者 头真的好大哦 所有, 如有侵权,请联系我们删除。