(1)signal模块介绍
信号是一种进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号,处理完信号后再继续原来的程序执行流程。
signal包负责在python程序内部处理信号,典型的操作包括预设信号处理函数,暂停并等待信号,以及定时发出SIGALRM等。
windows和Linux都可以使用signal库,但是部分信号只支持Linux,比如signal.SIGALRM。所以使用signal库时要注意平台,详情可以参考文档:signal --- 设置异步事件处理器 --- Python 3.13.3 文档
python自带的处理信号的库是signal。
(2)使用示例
1.预设信号处理函数
python
# -*- coding:utf-8 -*-
import signal
def handler(sig, frame):
# 处理函数handler的形参是固定的
# sig代表信号值,是一个整数,信号编号
# frame 参数,是一个栈帧对象,它包含当前调用栈的信息(如局部变量、函数调用链等)
print(f"sig: {sig}")
print(f"frame: {frame}")
if __name__ == "__main__":
signal.signal(signal.SIGTSTP, handler)
signal.pause()
上述代码含义:当接收到停止终端信号(signal.SIGTSTP),调用处理函数handler,输出信号值和进程栈信息。

由结果可知,接收到的信号值为20,frame值为: <frame at 0xb670fc30, file '1.py', line 12, code <module>>
解释:
- signal.signal(signalnum, handler)函数有两个参数:signalnum: 某个信号,比如signal.SIGTSTP;handler: 信号处理函数。
- signal调用hander的时候,会传递两个参数:signum: 这个就是信号值,也就是signalnum;frame: 这个参数是用来获得信号发生时,进程栈的情况。
2.定时发出信号
使用的函数是:signal.alarm()
该函数被用于在一定时间之后,向进程自身发送SIGALRM信号。
python
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import signal
import time
import datetime
def handler(sig, frame):
print(datetime.datetime.now())
print("handler function")
if __name__ == "__main__":
signal.signal(signal.SIGALRM, handler)
print(datetime.datetime.now())
signal.alarm(5)
time.sleep(10)
print(datetime.datetime.now())
print("main function")
上述代码含义:程序运行5秒后向自身发送SIGALRM信号,调用handler函数。主程序运行10秒之后打印信息。为了证明signal.alarm(5)确实生效了,特意添加了一些打印时间的信息。运行结果如下:

由上图输出结果可知:
11:32:37,程序开始运行
11:32:42,handler函数被调用起来了,时间经过了11:32:42 - 11:32:37 = 5秒。说明signal.alarm(5)生效了。
11:32:47,从程序运行,到现在共10秒,接着输出主函数后面的内容。
程序总共耗时10秒钟,由此也可以推断出,signal.alarm()函数不是阻塞式的。
以上程序是在linux上运行的,如果换到windows上运行会报错:
AttributeError: module 'signal' has no attribute 'SIGALRM'

原因前面讲过了,部分信号只支持Linux
(3)常见signal信号
系统中的信号载体都有一个名字,以"SIG"开头,每个信号都有对应的编号。
注意信号是软件中断。
不存在编号为0的信号。
1.Linux系统上有哪些信号
执行命令man 7 signal或者kill -l查看
man 7 signal

kill -l

说明:
- SIGHUP - 1: 连接断开。
- SIGINT - 2:中断信号,例如键盘按下:CTRL + C。
- SIGQUIT - 3:退出信号,例如键盘按下: CTRL + \。可以进去python解释器,按下ctrl+\就会退出Python解释器。
- SIGILL - 4:非法(硬件)指令
- SIGTRAP - 5: 指示一个实现定义的硬件故障。执行断点指令时,常用此信号将控制转移至调试程序。(断点调试用?)
- SIGABRT - 6: 夭折信号,进程调用abort函数时产生这种信号,进程异常终止。
- SIGBUS - 7: 内存故障,产生此种信号。
- SIGFPE - 8: 表示一个算术运算异常,如除以0、浮点溢出等。
- SIGKILL - 9: 终止信号,例如:kill -9 xxpid,用于进程的立即终止,不能被忽略或阻止,进程与其线程一起终止,适用于无响应的进程。暴力~
- SIGUSR1 - 10: 用户定义的信号,可用于应用程序。
- SIGSEGV - 11: 硬件异常产生的信号,比如除数为0、无效的内存引用等。
- SIGUSR2 - 12: 用户定义的信号,可用于应用程序。
- SIGPIPE - 13: 在管道的读进程已终止后,一个进程写此管道,会产生该信号。店已打烊,请勿来访~
- SIGALRM - 14: 闹钟信号,由alarm函数设置的定时器超时后产生此信号。
- SIGTERM - 15: 终止信号。软终止,kill命令默认发送SIGTERM信号。该信号让程序有机会在退出之前做好清理工作,优雅地终止。和kill -9相比,SIGTERM不会杀死子进程。
- SIGSTKFLT - 16: 仅由Linux定义,它出现在Linux的早期版本,企图用于数据协处理器的栈故障。该信号并非由内核产生,但仍保留以向后兼容。
- SIGCHLD - 17: 子进程状态改变。当一个进程终止或停止时,SIGCHLD信号被送给其父进程。需要父进程去捕捉,因为SIGCHLD信号默认是忽略的。
- SIGCOUT - 18: 使暂停进程继续。系统会根据进程状态判定默认动作,如果接收到该信号的进程是停止状态,默认动作是继续;否则默认动作是忽略此信号。
- SIGSTOP - 19: 停止
- SIGTSTP - 20: 停止终端输入。例如:键盘按下CTRL + Z。
- SIGTTIN - 21: 当一个后台进程组进程试图读其控制终端时,终端驱动程序产生此信号。
- SIGTTOU - 22: 当一个后台进程组进程试图写其控制终端时,终端驱动程序产生此信号。
- SIGURG - 23: 在网络连接上传来带外的数据。通知进程已经发生了一个紧急情况。
- SIGXCPU - 24: 超过软CPU时间(疑惑:软CPU时间指的是发生中断CPU做指定请求处理消耗的时间?)限制,则产生此信号。
- SIGXFSZ - 25: 如果进程超过了其软文件长度限制,则产生此信号。
- SIGVTALRM - 26: 当一个由setitimer(2)函数设置的虚拟间隔时间已经超时时,产生此信号。
- SIGPROF - 27: 当setitimer(2)函数设置的梗概统计间隔定时器已经超时时产生此信号。
- SIGWINCH - 28: 内核维持与每个终端或伪终端相关联窗口的大小。如果ioctl更改了窗口大小,内核会将SIGWINCH信号发送给前台进程组。
- SIGIO - 29: 此信号指示一个异步I/O事件。
- SIGPWR - 30: 主要用于不间断电源(UPS)的系统。如果电源失效,则UPS启动,系统如果能依靠蓄电池继续运行,无需做任何处理;如果蓄电池也不能使系统继续运行,此时就会发送SIGPWR信号给init进程,然后由init进程处理停机操作。
- SIGSYS - 31: 当进程执行了一条机器指令,但是参数却是无效的,会产生该信号。
- SIGRTMIN - 32: 编号32之后的信号都是自定义信号,还未接触,以后用到了在这补充~
2.常见windows信号
连接挂断
signal.SIGUP
非法指令
signal.SIGILL
终止进程
SIGINT信号编号为2,当按下键盘CTRL+c组合键时进程会收到此信号,用于终止进程。
signal.SIGINT
暂停进程CTRL+z
signal.SIGSTP
杀死进程,此信号不能被捕获或忽略。
SIGKILL信号用于强制杀死进程,此信号进程无法忽视,直接在系统层面将进程杀死,所以在Python中它是不能监听的。
signal.SIGKILL
终端退出
signal.SIGQUIT
终止信号,软件终止信号。
当终端用户输入kill sigerm pid时对应PID的进程会接收到此信号,此信号进程是可以捕获并指定函数处理。比如做一下程序清理等工作,当然也是可以忽视此信号的。
signal.SIGTERM
继续执行暂停进程
signal.SIGCONT
end