当前位置: 首页 > 面试题库 >

Python:当父异常终止时,如何杀死子进程?

黄德明
2023-03-14
问题内容

子进程开始于

subprocess.Popen(arg)

有没有办法确保在父异常终止时将其杀死?我需要在Windows和Linux上都能使用。

编辑:

subprocess.Popen(arg)如果存在使用其他启动进程的方法的解决方案,则可以放宽启动子进程的要求。


问题答案:

呵呵,我昨天自己在研究这个!假设您无法更改子程序:

在Linux上,prctl(PR_SET_PDEATHSIG,...)可能是唯一可靠的选择。(如果绝对有必要终止子进程,那么您可能希望将终止信号设置为SIGKILL而不是SIGTERM;链接到的代码使用SIGTERM,但是子级确实可以选择忽略SIGTERM。

在Windows上,最可靠的选择是使用Job对象。想法是创建一个“作业”(一种用于流程的容器),然后将子流程放入作业中,并设置魔术选项,指出“当没有人握住该作业的“手柄”时,然后杀死其中的进程”。默认情况下,作业的唯一“句柄”是父进程持有的句柄,并且当父进程死掉时,操作系统将遍历并关闭其所有句柄,然后注意这意味着没有用于工作。因此,它会按要求杀死孩子。包含使用该win32api模块执行此操作的示例代码。该代码使用CreateProcess发射子,而不是subprocess.Popen。原因是他们需要为生成的子项获取一个“进程句柄”,并CreateProcess默认将其返回。如果您愿意使用subprocess.Popen,那么这是该答案中代码的(未经html" target="_blank">测试的)副本,它使用subprocess.PopenOpenProcess代替CreateProcess

import subprocess
import win32api
import win32con
import win32job

hJob = win32job.CreateJobObject(None, "")
extended_info = win32job.QueryInformationJobObject(hJob, win32job.JobObjectExtendedLimitInformation)
extended_info['BasicLimitInformation']['LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
win32job.SetInformationJobObject(hJob, win32job.JobObjectExtendedLimitInformation, extended_info)

child = subprocess.Popen(...)
# Convert process id to process handle:
perms = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA
hProcess = win32api.OpenProcess(perms, False, child.pid)

win32job.AssignProcessToJobObject(hJob, hProcess)

从技术上讲,这里有一个很小的比赛条件,以防孩子在PopenOpenProcess呼叫之间死亡,您可以决定是否要担心这一点。

使用作业对象的一个​​缺点是,在Vista或Win7上运行时,如果从Windows
Shell启动程序(即,通过单击图标),则可能已经分配了一个作业对象并尝试创建一个作业对象。新的作业对象将失败。Win8可以解决此问题(通过允许嵌套作业对象),或者如果您的程序是从命令行运行的,那么应该可以。

如果您 可以
修改子级(例如,像使用时一样multiprocessing),那么最好的选择可能是以某种方式将父级的PID传递给子级(例如,作为命令行参数,或者在的args=参数中multiprocessing.Process),然后:

在POSIX上:在子级中生成一个os.getppid()偶尔会调用的线程,如果返回值停止匹配从父级传入的pid,则调用os._exit()。(这种方法可移植到包括OS
X在内的所有Unix上,而prctl窍门是特定于Linux的。)

在Windows上:在使用OpenProcess和的子代中产生一个线程os.waitpid。使用ctypes的示例:

from ctypes import WinDLL, WinError
from ctypes.wintypes import DWORD, BOOL, HANDLE
# Magic value from http://msdn.microsoft.com/en-us/library/ms684880.aspx
SYNCHRONIZE = 0x00100000
kernel32 = WinDLL("kernel32.dll")
kernel32.OpenProcess.argtypes = (DWORD, BOOL, DWORD)
kernel32.OpenProcess.restype = HANDLE
parent_handle = kernel32.OpenProcess(SYNCHRONIZE, False, parent_pid)
# Block until parent exits
os.waitpid(parent_handle, 0)
os._exit(0)

这避免了我提到的作业对象的任何可能的问题。

如果您想真正确定,那么可以组合所有这些解决方案。

希望有帮助!



 类似资料:
  • 问题内容: 我想尽可能快地重复执行子过程。但是,有时该过程将花费很长时间,因此我想取消它。我使用signal.signal(…),如下所示: 但有时这段代码将尝试阻止下一轮执行。停止test / home / lu / workspace / 152 / treefit / test2超时/ bin / sh:/ home / lu / workspace / 153 / squib_driver

  • 问题内容: 我正在尝试编写一个python程序来测试用C编写的服务器。python程序使用以下模块启动已编译的服务器: 这可以正常工作,但是如果python程序由于错误而意外终止,则生成的进程将保持运行状态。我需要一种方法来确保如果python程序意外退出,服务器进程也会被杀死。 更多细节: 仅Linux或OSX操作系统 服务器代码无法以任何方式修改 问题答案: 我需要一个函数来终止该过程: 或许

  • 问题内容: 我从python脚本生成了5个不同的进程,如下所示: 我的问题是,当父进程(主脚本)以某种方式被杀死时,子进程继续运行。 当父进程被杀死时,有没有办法杀死这样生成的子进程? 编辑:我正在尝试: 但这似乎不起作用 问题答案: 我自己也遇到了同样的问题,我有以下解决方案: 打电话之前,您可以设置。然后如此处所述python.org multiprocessing 进程退出时,它将尝试终止其

  • 问题内容: 我有一个程序生成并与CPU繁重,不稳定的进程通信,而不是由我创建的。如果我的应用程序崩溃或被杀死,我也希望子进程也被杀死,因此用户不必跟踪它们并手动杀死它们。 我知道以前已经讨论过该主题,但是我已经尝试了所有描述的方法,但似乎没有一种方法能够经受住测试的考验。 我知道这是有可能的,因为终端一直在这样做。如果我在终端中运行某些程序并杀死该终端,则这些东西总是会死掉。 我试过了,双叉和。不

  • 问题内容: 我正在使用child_process.spawn()从在Ubuntu上运行的Node.JS应用程序启动脚本。据我所知,标准的分叉或生成的* nix进程通常不会在父进程死后死亡,但是当从Node.JS生成进程时,它们似乎在我的应用程序崩溃或被ctrl-c等终止时被杀死。 。 为什么会这样,并且有解决办法?我似乎在child_process API中找不到任何明显的选项。 我的应用程序启动

  • 问题内容: 我正在python中使用subprocess模块​​运行一些shell脚本。如果shell脚本运行时间很长,我想杀死该子进程。我认为如果将其传递给我的陈述就足够了。 这是代码: 我已经用一些运行120秒的shell脚本测试了此调用。我期望子进程在30秒后被杀死,但是实际上该进程正在完成120秒脚本,然后引发了Timeout Exception。现在的问题是如何通过超时杀死子进程? 问题