문제

창문에서 subprocess.Popen.terminate Win32를 호출합니다 TerminalProcess. 그러나 내가 보는 행동은 내가 종료하려는 과정의 아동 과정이 여전히 실행되고 있다는 것입니다. 왜 그런 겁니까? 프로세스에서 시작된 모든 아동 프로세스가 사망했는지 어떻게해야합니까?

도움이 되었습니까?

해결책

사용하여 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)

다른 팁

사용 taskkill 이랑 /T 깃발

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

TaskKill의 플래그에는 다음 문서가 있습니다.

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.

또는 comtypes와 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)

이것은 어려운 일입니다. Windows는 실제로 프로세스 공간에 프로세스 트리를 저장하지 않습니다. 과정을 종료하고 아이들이 죽어야한다고 지정할 수도 없습니다.

그 주변의 한 가지 방법은 TaskKill을 사용하여 나무 전체를 엉망으로 만드는 것입니다.

이를 수행하는 또 다른 방법 (최상위 프로세스를 생성한다고 가정)은 이런 종류의 물건을 염두에두고 개발 된 모듈을 사용하는 것입니다. http://benjamin.smedbergs.us/blog/tag/killableprocess/

일반적으로 직접 수행하려면 목록을 거꾸로 구축하는 데 시간을 보내야합니다. 즉, 프로세스는 부모에게 포인터를 저장하지만 부모는 자녀에 대한 정보를 저장하지 않는 것으로 보입니다.

따라서 시스템의 모든 프로세스 (실제로 어렵지 않음)를 살펴본 다음 부모 프로세스 필드를 보면서 점을 수동으로 연결해야합니다. 그런 다음 관심있는 나무를 선택하고 모든 것을 걸어 각 노드를 하나씩 죽입니다.

부모가 죽을 때 Windows는 자녀의 부모 포인터를 업데이트하지 않으므로 나무에 간격이있을 수 있습니다. 나는 당신이 그것에 대해 할 수있는 일을 모릅니다.

다음은 작업 객체 메소드에 대한 예제 코드이지만 대신 subprocess 사용합니다 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)

아이들을 신약에 넣으십시오 작업 대상, 그러면 모든 아이들을 죽일 수 있습니다

나는 같은 문제가 있었고 어린이 살해 "/t"를위한 옵션으로 Windows Command를 통해 프로세스를 죽였습니다.

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)

나는 Kevin-Smyth의 대답을 사용하여 a를 만들었습니다 드롭 인 교체 ~을 위한 subprocess.Popen 익명의 작업 대상에서 생성 된 아동 프로세스를 제한하여 닫기에 종료하도록 설정합니다.

# coding: utf-8

from subprocess import Popen
import subprocess
import win32job
import win32process
import win32api


class JobPopen(Popen):
    """Start a process in a new Win32 job object.

    This `subprocess.Popen` subclass takes the same arguments as Popen and
    behaves the same way. In addition to that, created processes will be
    assigned to a new anonymous Win32 job object on startup, which will
    guarantee that the processes will be terminated by the OS as soon as
    either the Popen object, job object handle or parent Python process are
    closed.
    """

    class _winapijobhandler(object):
        """Patches the native CreateProcess function in the subprocess module
        to assign created threads to the given job"""

        def __init__(self, oldapi, job):
            self._oldapi = oldapi
            self._job = job

        def __getattr__(self, key):
            if key != "CreateProcess":
                return getattr(self._oldapi, key)  # Any other function is run as before
            else:
                return self.CreateProcess  # CreateProcess will call the function below

        def CreateProcess(self, *args, **kwargs):
            hp, ht, pid, tid = self._oldapi.CreateProcess(*args, **kwargs)
            win32job.AssignProcessToJobObject(self._job, hp)
            win32process.ResumeThread(ht)
            return hp, ht, pid, tid

    def __init__(self, *args, **kwargs):
        """Start a new process using an anonymous job object. Takes the same arguments as Popen"""

        # Create a new job object
        self._win32_job = self._create_job_object()

        # Temporarily patch the subprocess creation logic to assign created
        # processes to the new job, then resume execution normally.
        CREATE_SUSPENDED = 0x00000004
        kwargs.setdefault("creationflags", 0)
        kwargs["creationflags"] |= CREATE_SUSPENDED
        try:
            _winapi = subprocess._winapi  # Python 3
            _winapi_key = "_winapi"
        except AttributeError:
            _winapi = subprocess._subprocess  # Python 2
            _winapi_key = "_subprocess"
        try:
            setattr(subprocess, _winapi_key, JobPopen._winapijobhandler(_winapi, self._win32_job))
            super(JobPopen, self).__init__(*args, **kwargs)
        finally:
            setattr(subprocess, _winapi_key, _winapi)

    def _create_job_object(self):
        """Create a new anonymous job object"""
        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)
        return hjob

    def _close_job_object(self, hjob):
        """Close the handle to a job object, terminating all processes inside it"""
        if self._win32_job:
            win32api.CloseHandle(self._win32_job)
            self._win32_job = None

    # This ensures that no remaining subprocesses are found when the process
    # exits from a `with JobPopen(...)` block.
    def __exit__(self, exc_type, value, traceback):
        super(JobPopen, self).__exit__(exc_type, value, traceback)
        self._close_job_object(self._win32_job)

    # Python does not keep a reference outside of the parent class when the
    # interpreter exits, which is why we keep it here.
    _Popen = subprocess.Popen  
    def __del__(self):
        self._Popen.__del__(self)
        self._close_job_object(self._win32_job)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top