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()
def start_auto_cleanup_subprocess(target_pid):
cleanup_script = f"""
import os
import psutil
import signal
from time import sleep
try:
# Block until stdin is closed which means the parent process
# has terminated.
input()
except Exception:
# Should be an EOFError, but if any other exception happens,
# assume we should respond in the same way.
pass
if not psutil.pid_exists({target_pid}):
# Target process has already exited, so nothing to do.
exit()
os.kill({target_pid}, signal.SIGTERM)
for count in range(10):
if not psutil.pid_exists({target_pid}):
# Target process no longer running.
exit()
sleep(1)
os.kill({target_pid}, signal.SIGKILL)
# Don't bother waiting to see if this works since if it doesn't,
# there is nothing else we can do.
"""
return Popen(
[
sys.executable, # Python executable
'-c', cleanup_script
],
stdin=subprocess.PIPE
)
4条答案
按热度按时间of1yzvn41#
嘿,我昨天还在研究呢!假设你不能修改子程序:
在Linux上,
prctl(PR_SET_PDEATHSIG, ...)
可能是唯一可靠的选择。(如果绝对有必要终止子进程,那么您可能希望将终止信号设置为SIGKILL而不是SIGTERM;您链接到的代码使用SIGTERM,但子程序可以根据需要选择忽略SIGTERM。)在Windows上,最可靠的选项是使用Job object。(一种进程容器),然后将子进程放入作业中,并设置“当没有人持有此作业的”句柄“时,则终止其中的进程”的神奇选项。默认情况下,这个作业的唯一“句柄”是你的父进程持有的那个句柄,当父进程死亡时,操作系统会检查并关闭它所有的句柄,然后注意到这意味着这个作业没有打开的句柄,于是它就杀死了这个子进程,如所要求的那样。(如果您有多个子进程,可以将它们全部分配给同一个作业。)This answer提供了执行此操作的示例代码,使用
win32api
模块。该代码使用CreateProcess
启动子进程,而不是subprocess.Popen
。原因是它们需要为派生的子进程获取一个“进程句柄”,而CreateProcess
在默认情况下返回此句柄。(未测试)该答案中的代码副本,使用subprocess.Popen
和OpenProcess
而不是CreateProcess
:从技术上讲,这里有一个很小的竞争条件,以防孩子在
Popen
和OpenProcess
调用之间死亡,你可以决定是否要考虑这个问题。使用作业对象的一个缺点是,当在Vista或Win7上运行时,如果你的程序是从Windows shell启动的(即,通过点击图标),那么可能会出现already be a job object assigned,并且试图创建一个新的作业对象会失败。Win8修复了这个问题(通过允许嵌套作业对象),或者如果你的程序是从命令行运行的,那么它应该是好的。
如果您 * 可以 * 修改子进程(例如,使用
multiprocessing
时),那么最好的选择可能是以某种方式将父进程的PID传递给子进程(例如,作为命令行参数,或在args=
参数中传递给multiprocessing.Process
),然后:在POSIX上:在子线程中生成一个线程,该线程只是偶尔调用
os.getppid()
,如果返回值不再与从父线程传入的pid匹配,则调用os._exit()
。(这种方法可移植到所有的Unix,包括OS X,而prctl
技巧是Linux特有的。)在Windows上:在使用
OpenProcess
和os.waitpid
的子系中衍生执行绪。使用ctypes的范例:这避免了我提到的作业对象可能出现的任何问题。
如果你想非常非常确定,那么你可以把所有这些解决方案结合起来。
希望这对你有帮助!
kmb7vmvb2#
Popen对象提供了终止和终止方法。
https://docs.python.org/2/library/subprocess.html#subprocess.Popen.terminate
它们会为您发送SIGTERM和SIGKILL信号。您可以执行类似以下操作:
最新消息:
您是正确的--上面的代码不能防止进程硬崩溃或被人终止。在这种情况下,您可以尝试将子进程 Package 在一个类中,并使用轮询模型来监视父进程。请注意,psutil是非标准的。
在这个例子中我运行'ping -t localhost' B/c,它将永远运行。如果你杀死父进程,子进程(ping命令)也将被杀死。
tpgth1q73#
据我所知,
PR_SET_PDEATHSIG
解决方案在父进程中运行任何线程时都可能导致死锁,因此我不想使用它,并找到了另一种方法。我创建了一个单独的自动终止进程,它检测父进程何时完成,并杀死作为其目标的另一个子进程。要完成此操作,您需要
pip install psutil
,然后编写类似于以下内容的代码:这与我没有注意到的https://stackoverflow.com/a/23436111/396373类似,但我认为我提出的方法更容易使用,因为作为清理目标的进程是由父进程直接创建的。还要注意,没有必要轮询父进程的状态,尽管在终止序列期间,如果您想尝试终止、监视然后如果终止不能迅速起作用则将其杀死。
xpszyzbs4#
使用SetConsoleCtrlHandler钩住进程的出口,然后杀死子进程。我想我在这方面做得有点过火了,但它是有效的:)
kill_proc_tree取自:
subprocess: deleting child processes in Windows