在 Python 信号处理器中调用 print 是否安全?
Is it safe to call print in a Python signal handler?

原始链接: https://iafisher.com/2026/08/sigprint

Python 的信号处理与 C 语言不同,因为它会将用户提供的函数推迟到解释器处于一致状态时执行,从而绕过了传统的底层限制。然而,Python 的信号处理程序本质上是可重入的,这意味着信号可能会中断处理程序自身。 一项涉及快速信号轰炸的压力测试表明,这种重入性可能会触发 `RuntimeError`——特别是在像 `print` 这样的函数向缓冲区写入内容时被中断的情况下。虽然这证明了极端条件可能导致程序崩溃,但这在实际应用中几乎不是问题。与 C 语言中不安全的信号处理可能导致静默损坏或死锁不同,Python 的这种行为会产生清晰的异常。尽管如此,不在信号处理程序中执行繁重的工作仍然是最佳实践。

这篇 Hacker News 讨论探讨了在 Python 信号处理程序中使用 `print()` 的危险性。 讨论中的共识是,POSIX 信号在设计上存在固有缺陷。由于信号处理程序会异步中断代码执行,因此它们仅限于使用极少数“异步信号安全”(async-signal-safe)的函数。尝试执行复杂的运算(如 `print()`)可能会导致重入问题、死锁或程序崩溃。 尽管 Python 通过在 C 处理程序中设置标志并将执行推迟到解释器来屏蔽了部分复杂性,但如果用户在处理程序内执行非原子操作,仍会面临风险。经验丰富的评论者强烈建议不要在信号处理程序内执行任何“实际工作”。相反,他们建议: * **设置标志**或使用主循环定期检查的原子变量。 * **使用 `signal.set_wakeup_fd()`** 将信号写入文件描述符,随后可由事件循环安全地轮询。 * **使用 `signalfd`**(仅限 Linux)或配合 `sigwait()` 的专用线程,以可预测的同步方式处理信号。 总之,该讨论强调了在多线程应用程序中管理信号极其困难,且信号仍然是竞态条件和系统不稳定的主要来源。
相关文章

原文
“These systems collect and process.”

We learned earlier that because Python has two signal handlers, the onerous restrictions on what functions a signal handler may call do not apply to Python, because CPython does not call the user-supplied Python signal handler inside the low-level C signal handler, where those restrictions do apply, but arranges for it to be called later, when the interpreter is in a consistent state.

We also learned that Python signal handlers are unexpectedly reentrant – if a signal arrives while a Python signal handler is running, the signal handler can be called again in the middle of the first call.

What happens if a signal handler is reentered in the middle of a call to print? Let's stress-test it by sending ourselves a rapid barrage of signals:

import os, signal, subprocess

def sighandler(_signo, _frame):
    print("signal received")

signal.signal(signal.SIGUSR1, sighandler)
subprocess.run("for x in {1..50}; do kill -USR1 %s; done" % os.getpid(), shell=True)

Running this program on my machine produced:

  File "multiple_signals.py", line 6, in sighandler
    print("signal received")
  File "multiple_signals.py", line 6, in sighandler
    print("signal received")
  File "multiple_signals.py", line 6, in sighandler
    print("signal received")
  [Previous line repeated 2 more times]
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>

The test program shows that under extreme circumstances, calling print in a signal handler may cause your program to crash. I want to emphasize that this requires extreme circumstances: it is unlikely that a real program would face these conditions, and even so, failing with an exception is more palatable than the possible consequences of unsafe signal handlers in C, which include deadlock, corrupted data structures, and silent failures. So I view this as another bit of signals trivia and not a practical consideration for writing signal handlers – though I still advise against doing non-trivial work in a signal handler.

联系我们 contact @ memedata.com