子进程开始于
subprocess.Popen(arg)
当父母异常终止时,有没有办法确保它被杀死?我需要它在 Windows 和 Linux 上都能工作。我知道这个 适用于 Linux 的解决方案。
编辑:
使用 subprocess.Popen(arg)
启动子进程的要求可以放宽,如果存在使用不同的启动进程方法的解决方案。
原文由 user443854 发布,翻译遵循 CC BY-SA 4.0 许可协议
子进程开始于
subprocess.Popen(arg)
当父母异常终止时,有没有办法确保它被杀死?我需要它在 Windows 和 Linux 上都能工作。我知道这个 适用于 Linux 的解决方案。
编辑:
使用 subprocess.Popen(arg)
启动子进程的要求可以放宽,如果存在使用不同的启动进程方法的解决方案。
原文由 user443854 发布,翻译遵循 CC BY-SA 4.0 许可协议
Popen 对象提供终止和终止方法。
https://docs.python.org/2/library/subprocess.html#subprocess.Popen.terminate
这些为您发送 SIGTERM 和 SIGKILL 信号。您可以执行类似于以下操作的操作:
from subprocess import Popen
p = None
try:
p = Popen(arg)
# some code here
except Exception as ex:
print 'Parent program has exited with the below error:\n{0}'.format(ex)
if p:
p.terminate()
更新:
你是对的——上面的代码不能防止硬崩溃或有人杀死你的进程。在这种情况下,您可以尝试将子进程包装在一个类中,并使用轮询模型来监视父进程。 请注意 psutil 是非标准的。
import os
import psutil
from multiprocessing import Process
from time import sleep
class MyProcessAbstraction(object):
def __init__(self, parent_pid, command):
"""
@type parent_pid: int
@type command: str
"""
self._child = None
self._cmd = command
self._parent = psutil.Process(pid=parent_pid)
def run_child(self):
"""
Start a child process by running self._cmd.
Wait until the parent process (self._parent) has died, then kill the
child.
"""
print '---- Running command: "%s" ----' % self._cmd
self._child = psutil.Popen(self._cmd)
try:
while self._parent.status == psutil.STATUS_RUNNING:
sleep(1)
except psutil.NoSuchProcess:
pass
finally:
print '---- Terminating child PID %s ----' % self._child.pid
self._child.terminate()
if __name__ == "__main__":
parent = os.getpid()
child = MyProcessAbstraction(parent, 'ping -t localhost')
child_proc = Process(target=child.run_child)
child_proc.daemon = True
child_proc.start()
print '---- Try killing PID: %s ----' % parent
while True:
sleep(1)
在此示例中,我运行将永远运行的“ping -t localhost”b/c。如果杀死父进程,子进程(ping 命令)也将被杀死。
原文由 Nick 发布,翻译遵循 CC BY-SA 3.0 许可协议
2 回答5.1k 阅读✓ 已解决
2 回答1.1k 阅读✓ 已解决
4 回答1.4k 阅读✓ 已解决
3 回答1.3k 阅读✓ 已解决
3 回答1.2k 阅读✓ 已解决
1 回答1.7k 阅读✓ 已解决
1 回答1.2k 阅读✓ 已解决
呵呵,我昨天刚在研究这个!假设您不能更改子程序:
在 Linux 上,
prctl(PR_SET_PDEATHSIG, ...)
可能是唯一可靠的选择。 (如果绝对有必要杀死子进程,那么您可能希望将死亡信号设置为 SIGKILL 而不是 SIGTERM;您链接到的代码使用 SIGTERM,但如果孩子愿意,它确实可以选择忽略 SIGTERM。 )在 Windows 上,最可靠的选择是使用 Job 对象。这个想法是创建一个“作业”(一种进程容器),然后将子进程放入作业中,然后设置神奇的选项“当没有人持有此作业的’句柄’时,然后终止其中的进程”。默认情况下,作业的唯一“句柄”是您的父进程持有的那个,当父进程死亡时,操作系统将遍历并关闭其所有句柄,然后注意这意味着没有打开的句柄工作。因此,它会按照要求杀死孩子。 (如果您有多个子进程,您可以将它们全部分配给同一个作业。) 这个答案 有用于执行此操作的示例代码,使用
win32api
模块。该代码使用CreateProcess
来启动孩子,而不是subprocess.Popen
。原因是他们需要为生成的孩子获取“进程句柄”,并且CreateProcess
默认返回它。如果您更愿意使用subprocess.Popen
,那么这是该答案中代码的(未经测试的)副本,它使用subprocess.Popen
和OpenProcess
而不是CreateProcess
:从技术上讲,这里有一个微小的竞争条件,以防孩子在
Popen
和OpenProcess
调用之间死亡,您可以决定是否要为此担心。使用作业对象的一个缺点是,当在 Vista 或 Win7 上运行时,如果您的程序是从 Windows shell 启动的(即,通过单击图标),那么可能 已经分配了一个作业对象 并试图创建一个新的作业对象将失败。 Win8 修复了这个问题(通过允许嵌套作业对象),或者如果您的程序是从命令行运行的,那么它应该没问题。
如果您 可以 修改子项(例如,像使用
multiprocessing
时一样),那么最好的选择可能是以某种方式将父项的 PID 传递给子项(例如,作为命令行参数,或在args=
multiprocessing.Process
的参数,然后:在 POSIX 上:在仅偶尔调用
os.getppid()
的子进程中生成一个线程,如果返回值不再匹配从父进程传入的 pid,则调用os._exit()
。 (这种方法适用于所有 Unix,包括 OS X,而prctl
技巧是特定于 Linux 的。)在 Windows 上:在使用
OpenProcess
和os.waitpid
的子进程中生成一个线程。使用 ctypes 的示例:这避免了我提到的作业对象的任何可能问题。
如果你想非常非常确定,那么你可以结合所有这些解决方案。
希望有帮助!