48

Windows では、subprocess.Popen.terminatewin32 のTerminalProcess. ただし、終了しようとしているプロセスの子プロセスがまだ実行されているという動作が見られます。何故ですか?プロセスによって開始されたすべての子プロセスが強制終了されるようにするにはどうすればよいですか?

4

7 に答える 7

72

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)
于 2010-11-19T21:11:59.047 に答える
42

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)
于 2012-05-31T09:21:14.873 に答える
10

Job オブジェクト メソッドのコード例を次に示しますが、代わりsubprocesswin32api.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)
于 2012-10-17T20:25:37.217 に答える
8

これは難しいことです。Windows は、実際にはプロセス ツリーをプロセス空間に格納しません。また、プロセスを終了して、その子プロセスも終了するように指定することもできません。

これを回避する 1 つの方法は、taskkill を使用して、ツリー全体を wack するように指示することです。

それを行う別の方法 (最上位プロセスを生成していると仮定) は、この種のことを念頭に置いて開発されたモジュールを使用することです: http://benjamin.smedbergs.us/blog/tag/killableprocess/

これを一般的に自分で行うには、リストを逆方向に作成するのに時間を費やす必要があります。つまり、プロセスはその PARENT へのポインターを格納しますが、親は子に関する情報を格納していないように見えます。

そのため、システム内のすべてのプロセスを確認する必要があり (実際にはそれほど難しくありません)、親プロセス フィールドを確認して手動でドットを接続する必要があります。次に、関心のあるツリーを選択して全体を歩き、各ノードを 1 つずつ順番に殺します。

Windows は、親が死亡したときに子の親ポインターを更新しないため、ツリーにギャップが生じる可能性があることに注意してください。それらについてあなたができることは何も知りません。

于 2009-08-05T02:12:55.490 に答える
6

子を NT Job オブジェクトに入れると、すべての子を殺すことができます

于 2009-08-05T04:30:00.807 に答える