使用作业对象的一个缺点是,在Vista或Win7上运行时,如果您的程序是从Windows shell启动的(即,通过单击图标),那么可能会有already be a job object assigned,尝试创建新的作业对象将失败。Win8解决了这个问题(允许作业对象被嵌套),或者如果程序是从命令行运行的,那么应该没问题。
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()
嘿,昨天我自己也在研究呢!假设您不能更改子程序:
在Linux上,
prctl(PR_SET_PDEATHSIG, ...)
可能是唯一可靠的选择。(如果绝对有必要终止子进程,那么您可能希望将终止信号设置为SIGKILL而不是SIGTERM;您链接到的代码使用SIGTERM,但是如果子进程愿意,它确实可以选择忽略SIGTERM。)在Windows上,最可靠的选项是使用Job object。其思想是创建一个“作业”(一种进程容器),然后将子进程放入该作业中,然后设置一个神奇的选项,即“当没有人持有此作业的“句柄”时,然后杀死其中的进程”。默认情况下,作业的唯一“句柄”是父进程持有的句柄,当父进程死亡时,操作系统将遍历并关闭其所有句柄,然后注意这意味着作业没有打开的句柄。所以它会按要求杀死孩子。(如果有多个子进程,则可以将它们全部分配给同一个作业。)This answer有用于执行此操作的示例代码,使用
win32api
模块。该代码使用CreateProcess
来启动子代,而不是subprocess.Popen
。原因是,它们需要为派生的子级获取“进程句柄”,并且默认情况下,CreateProcess
返回此值。如果您希望使用subprocess.Popen
,那么这里有一个(未测试的)该答案的代码副本,它使用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的示例:这避免了我提到的任何与作业对象有关的可能问题。
如果你真的,真的想确定,那么你可以把所有这些解决方案结合起来。
希望能有帮助!
Popen对象提供了terminate和kill方法。
https://docs.python.org/2/library/subprocess.html#subprocess.Popen.terminate
它们为你发出信号。 你可以做以下类似的事情:
更新:
您是对的——上面的代码无法防止硬崩溃或有人杀死您的进程。在这种情况下,您可以尝试在类中包装子进程,并使用轮询模型来监视父进程。 请注意psutil是非标准的。
在本例中,我运行的“ping-t localhost”b/c将永远运行。如果杀死父进程,子进程(ping命令)也将被杀死。
相关问题 更多 >
编程相关推荐