【发布时间】:2021-02-18 13:42:06
【问题描述】:
让我们有一个很小的程序来捕获(并忽略)SIGTERM 信号:
# nosigterm.py:
import signal
import time
def ignore(signum, frame):
print("Ignoring signal {}".format(signum))
if __name__ == '__main__':
signal.signal(signal.SIGINT, ignore)
signal.signal(signal.SIGTERM, ignore)
while True:
time.sleep(2)
print("... in loop ...")
当从另一个 python 脚本作为子进程执行时,发送 SIGTERM 会终止这个子进程,我觉得这很奇怪:
# parent_script.py:
import signal
import subprocess
import sys
args = [sys.executable, "nosigterm.py"]
prog = subprocess.Popen(args)
assert prog.poll() is None
prog.send_signal(signal.SIGTERM)
print("prog.poll(): {}".format(prog.poll()))
assert prog.poll() is None, "Program unexpectedly terminated after SIGTERM"
输出是:
$ python3 parent_script.py
prog.poll(): None
Traceback (most recent call last):
File "parent_script.py", line 13, in <module>
assert prog.poll() is None, "Program unexpectedly terminated after SIGTERM"
AssertionError: Program unexpectedly terminated after SIGTERM
你知道为什么会这样吗?
请注意,如果 nosigterm.py 作为独立的 Python 脚本 (python3 nosigterm.py) 执行,并且系统 kill 命令(在另一个终端中)发送 SIGTERM,它的行为应该如下:
$ python3 nosigterm.py
... in loop ...
... in loop ...
Ignoring signal 15
... in loop ...
... in loop ...
... in loop ...
我尝试了三个 python 版本(2.7、3.6 和 3.7)和两个 Linux 操作系统(CentOS 7 和 Debian 9),结果都一样。如果我将nosigterm.py 替换为用C 编写的捕获SIGTERM 的二进制应用程序(通过sigaction()),行为仍然没有改变,因此它一定与父python 进程有某种关联。
另请注意,Popen 参数 restore_signals=True/False 或 preexec_fn=os.setsid/os.setpgrp 也没有进行任何更改。
如果有人能帮助我理解这一点,我将不胜感激。谢谢。
【问题讨论】:
-
FWIW,我可以在 macOS 上的 Python 3.8.2 中重现,但不能在同一台机器上的 Python 3.9 中重现。
标签: python linux subprocess signals posix