복붙노트

[PYTHON] 하위 프로세스 : Windows에서 하위 프로세스 삭제

PYTHON

하위 프로세스 : Windows에서 하위 프로세스 삭제

Windows에서 subprocess.Popen.terminate는 win32의 TerminalProcess를 호출합니다. 그러나, 내가 보는 행동은 내가 종료하려고하는 프로세스의 자식 프로세스가 여전히 실행 중이다. 왜 그런가요? 프로세스에 의해 시작된 모든 하위 프로세스가 종료되었는지 어떻게 확인합니까?

해결법

  1. ==============================

    1.psutil을 사용하여 :

    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)
    
  2. ==============================

    2./ T 플래그와 함께 taskkill 사용

    / T 플래그와 함께 taskkill 사용

    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)
    
  3. ==============================

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

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

    한 가지 방법은 태스크 킬을 사용하여 전체 트리를 해킹하는 것입니다.

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

    이를 일반적으로 직접 수행하려면 목록을 거꾸로 작성해야합니다. 즉, 프로세스는 부모의 포인터를 저장하지만 부모는 자식에 대한 정보를 저장하지 않는 것처럼 보입니다.

    따라서 시스템의 모든 프로세스 (실제로 그리 어려운 것은 아닙니다)를 살펴본 다음 부모 프로세스 필드를보고 직접 점을 연결해야합니다. 그런 다음 관심있는 트리를 선택하고 모든 것을 걸어 다니면서 각 노드를 하나씩 차례대로 죽이십시오.

    부모가 죽으면 Windows는 자식의 부모 포인터를 업데이트하지 않으므로 트리에 간격이있을 수 있습니다. 나는 당신이 그 일들에 대해 할 수있는 어떤 일도 모르고 있습니다.

  4. ==============================

    4.아이들을 NT 작업 객체에 넣으면 모든 자식을 죽일 수 있습니다.

    아이들을 NT 작업 객체에 넣으면 모든 자식을 죽일 수 있습니다.

  5. ==============================

    5.다음은 Job 객체 메소드의 예제 코드이지만, 서브 프로세스 대신 win32api.CreateProcess

    다음은 Job 객체 메소드의 예제 코드이지만, 서브 프로세스 대신 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)
    
  6. ==============================

    6.나는 똑같은 문제가 있었고 윈도우 커맨드를 통해 자식 죽이는 옵션을 가진 프로세스를 죽이는 "/ T"

    나는 똑같은 문제가 있었고 윈도우 커맨드를 통해 자식 죽이는 옵션을 가진 프로세스를 죽이는 "/ 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)
    
  7. from https://stackoverflow.com/questions/1230669/subprocess-deleting-child-processes-in-windows by cc-by-sa and MIT license