如何解决为什么Python子进程无法正确捕获信号?
让我们有一个小小的程序,该程序应该捕获(并忽略)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,它的行为应为: / p>
$ 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),所有这些都具有相同的结果。如果我用用C编写的捕获SIGTERM的二进制应用程序(通过nosigterm.py
代替sigaction()
,则该行为仍然没有改变,因此它一定程度上与父python进程有关。
还要注意,Popen参数restore_signals=True/False
或preexec_fn=os.setsid/os.setpgrp
也没有做任何更改。
如果有人能帮助我理解这一点,我将不胜感激。谢谢。
解决方法
这是比赛条件。
您正在分叉并立即发送信号,因此这是子进程忽略它之前的一个竞赛。
此外,您的父脚本在检查脚本是否已死亡时具有竞争条件。您向脚本发出信号,并立即检查脚本是否已死,因此这是孩子在检查之前死亡的竞赛。
如果在发送信号之前添加time.sleep(1)
,则可以确保孩子赢得比赛,并因此获得预期的行为。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。