在 Linux 或类 Unix 系统中,信号(Signal)是一种用于进程间通信的机制,允许操作系统或其他进程向目标进程发送异步通知。
Python 的 signal
模块提供了对这些信号的访问和处理能力,使得我们可以在 Python 程序中捕获和响应特定的系统信号。
官方文档:signal — Set handlers for asynchronous events — Python 3.11.5 documentation
文章目录
📦 模块简介
signal
模块允许我们:
- 注册自定义的信号处理函数;
- 忽略特定的信号;
- 设置定时器,在指定时间后发送信号;
- 暂停程序执行,等待信号的到来。
需要注意的是,signal
模块主要在类 Unix 系统(如 Linux、macOS)中使用,某些功能在 Windows 上可能不被支持。
🔧 常用方法和属性
1. signal.signal(signalnum, handler)
用于为指定的信号注册处理。signalnum
是信号编号,handler
是信号处理程序,可以是自定义的函数(接受两个参数:signum 和 frame),也可以是特殊值 signal.SIG_IGN、 signal.SIG_DFL之一。
- signal.SIG_IGN:忽略该信号;
- signal.SIG_DFL:使用默认的信号处理方式。
import signal
def handler(signum, frame):
print(f"Received signal: {signum}")
signal.signal(signal.SIGINT, handler)
上述代码将 SIGINT
(通常由 Ctrl+C 触发)信号绑定到自定义的 handler
函数。
2. signal.alarm(seconds)
设置一个定时器,在指定的秒数后向进程发送 SIGALRM
信号。如果参数为 0,则取消之前设置的定时器。
import signal
import time
def timeout_handler(signum, frame):
print("Timeout!")
exit(1)
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(5) # 5 秒后触发 SIGALRM
time.sleep(10)
运行上述代码,程序将在 5 秒后打印 “Timeout!” 并退出。
3. signal.pause()
使程序暂停执行,直到接收到一个信号并处理完毕。
import signal
def handler(signum, frame):
print(f"Handled signal: {signum}")
signal.signal(signal.SIGUSR1, handler)
print("Waiting for signal...")
signal.pause()
执行上述代码后,程序将暂停,直到接收到 SIGUSR1
信号。
4. os.kill(pid, sig)
向指定的进程发送信号。其中 pid
是进程 ID,sig
是信号编号。
import os
import signal
os.kill(12345, signal.SIGTERM)
上述代码向进程 ID 为 12345 的进程发送 SIGTERM
(终止)信号。
🧪 实际应用示例
示例 1:处理用户自定义信号
import signal
import os
import time
def custom_handler(signum, frame):
print(f"Received signal: {signum}")
signal.signal(signal.SIGUSR1, custom_handler)
print(f"My PID is {os.getpid()}")
while True:
print("Waiting...")
time.sleep(3)
运行上述代码后,程序将每 3 秒打印一次 “Waiting…”。在另一个终端中,使用以下命令向该进程发送信号:
kill -USR1 <PID>
其中 <PID>
是程序运行时打印的进程ID。发送信号后,程序将调用 custom_handler
函数,打印接收到的信编号。
示例 2:忽略特定信号
import signal
import time
signal.signal(signal.SIGINT, signal.SIG_IGN)
print("Press Ctrl+C. It will be ignored.")
while True:
time.sleep(1)
运行上述代码后,按下 Ctrl+C,程序不会被中断,因为 SIGINT
信号被忽略了。
⚠️ 注意事项
-
线程限制:
signal
模块的信号处理函数只能在主线程中注册和执行。在子线程中注册信号处理函数将引发ValueError
异常。 -
平台兼容:某些信号(如
SIGALRM
)在 Windows 上不被支持,因此相关功能可能无法在 Windows 系统上正常工作。 -
信号处理的时机:Python 的信号处理是异步的,信号处理函数会在主线程的下一个安全点(如执行字节码指令时)被调用,而不是立即执行。