python处理signal(信号)

发布于:2025-05-28 ⋅ 阅读:(23) ⋅ 点赞:(0)

(1)signal模块介绍

信号是一种进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号,处理完信号后再继续原来的程序执行流程。

signal包负责在python程序内部处理信号,典型的操作包括预设信号处理函数,暂停并等待信号,以及定时发出SIGALRM等。

windows和Linux都可以使用signal库,但是部分信号只支持Linux,比如signal.SIGALRM。所以使用signal库时要注意平台,详情可以参考文档:signal --- 设置异步事件处理器 — Python 3.13.3 文档

python自带的处理信号的库是signal。

(2)使用示例

1.预设信号处理函数

# -*- 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信号。

#!/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