python windows process subprocess kill-process

python - subproceso: eliminar procesos secundarios en Windows



process subprocess (6)

Al usar psutil :

import psutil, os def kill_proc_tree(pid, including_parent=True): parent = psutil.Process(pid) children = parent.children(recursive=True) for child in children: child.kill() gone, still_alive = psutil.wait_procs(children, timeout=5) if including_parent: parent.kill() parent.wait(5) me = os.getpid() kill_proc_tree(me)

En Windows, subprocess.Popen.terminate llama a TerminalProcess de win32. Sin embargo, el comportamiento que veo es que los procesos hijos del proceso que estoy tratando de finalizar aún se están ejecutando. ¿Porqué es eso? ¿Cómo me aseguro de que se maten todos los procesos secundarios iniciados por el proceso?


Aquí hay un código de ejemplo para el método de objeto Job, pero en lugar de un subprocess , usa win32api.CreateProcess

import win32process import win32job startup = win32process.STARTUPINFO() (hProcess, hThread, processId, threadId) = win32process.CreateProcess(None, command, None, None, True, win32process.CREATE_BREAKAWAY_FROM_JOB, None, None, startup) 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) win32job.AssignProcessToJobObject(hJob, hProcess)


Esto es algo difícil de hacer. Windows no almacena un árbol de procesos en el espacio de proceso. Tampoco es posible finalizar un proceso y especificar que sus hijos también deben morir.

Una forma de evitarlo es usar taskkill y decirle a wack todo el árbol.

Otra forma de hacerlo (suponiendo que está generando el proceso de nivel superior) es utilizar un módulo que se desarrolló con este tipo de cosas en mente: http://benjamin.smedbergs.us/blog/tag/killableprocess/

Para hacer esto genéricamente para ti, tienes que dedicar un tiempo a construir la lista al revés. Es decir, un proceso almacena punteros a su PADRE, pero los padres parecen no almacenar información sobre los niños.

Por lo tanto, debe observar todos los procesos del sistema (que en realidad no es tan difícil) y luego, manualmente, conectar los puntos usted mismo mirando el campo de proceso principal. Luego, selecciona el árbol en el que estás interesado y lo recorre todo, matando a cada nodo uno por uno.

Tenga en cuenta que Windows no actualiza el puntero principal de un hijo cuando el padre muere, por lo que puede haber lagunas en su árbol. No estoy al tanto de nada que puedas hacer al respecto.


Ponga a los niños en un objeto NT Job , luego puede matar a todos los niños


Tuve el mismo problema y simplemente el proceso de matar a través del comando de Windows con la opción de matar niño "/ T"

def kill_command_windows(pid): ''''''Run command via subprocess'''''' dev_null = open(os.devnull, ''w'') command = [''TASKKILL'', ''/F'', ''/T'', ''/PID'', str(pid)] proc = subprocess.Popen(command, stdin=dev_null, stdout=sys.stdout, stderr=sys.stderr)


Usa taskkill con la bandera /T

p = subprocess.Popen(...) <wait> subprocess.call([''taskkill'', ''/F'', ''/T'', ''/PID'', str(p.pid)])

Los flags to taskkill tienen los siguientes documentos:

TASKKILL [/S system [/U username [/P [password]]]] { [/FI filter] [/PID processid | /IM imagename] } [/T] [/F] /S system Specifies the remote system to connect to. /U [domain/]user Specifies the user context under which the command should execute. /P [password] Specifies the password for the given user context. Prompts for input if omitted. /FI filter Applies a filter to select a set of tasks. Allows "*" to be used. ex. imagename eq acme* /PID processid Specifies the PID of the process to be terminated. Use TaskList to get the PID. /IM imagename Specifies the image name of the process to be terminated. Wildcard ''*'' can be used to specify all tasks or image names. /T Terminates the specified process and any child processes which were started by it. /F Specifies to forcefully terminate the process(es). /? Displays this help message.

O recorra el árbol de procesos usando comtypes y win32api:

def killsubprocesses(parent_pid): ''''''kill parent and all subprocess using COM/WMI and the win32api'''''' log = logging.getLogger(''killprocesses'') try: import comtypes.client except ImportError: log.debug("comtypes not present, not killing subprocesses") return logging.getLogger(''comtypes'').setLevel(logging.INFO) log.debug(''Querying process tree...'') # get pid and subprocess pids for all alive processes WMI = comtypes.client.CoGetObject(''winmgmts:'') processes = WMI.InstancesOf(''Win32_Process'') subprocess_pids = {} # parent pid -> list of child pids for process in processes: pid = process.Properties_(''ProcessID'').Value parent = process.Properties_(''ParentProcessId'').Value log.trace("process %i''s parent is: %s" % (pid, parent)) subprocess_pids.setdefault(parent, []).append(pid) subprocess_pids.setdefault(pid, []) # find which we need to kill log.debug(''Determining subprocesses for pid %i...'' % parent_pid) processes_to_kill = [] parent_processes = [parent_pid] while parent_processes: current_pid = parent_processes.pop() subps = subprocess_pids[current_pid] log.debug("process %i children are: %s" % (current_pid, subps)) parent_processes.extend(subps) processes_to_kill.extend(subps) # kill the subprocess tree if processes_to_kill: log.info(''Process pid %i spawned %i subprocesses, terminating them...'' % (parent_pid, len(processes_to_kill))) else: log.debug(''Process pid %i had no subprocesses.'' % parent_pid) import ctypes kernel32 = ctypes.windll.kernel32 for pid in processes_to_kill: hProcess = kernel32.OpenProcess(PROCESS_TERMINATE, FALSE, pid) if not hProcess: log.warning(''Unable to open process pid %i for termination'' % pid) else: log.debug(''Terminating pid %i'' % pid) kernel32.TerminateProcess(hProcess, 3) kernel32.CloseHandle(hProcess)