2009-08-05 43 views
31

Trên Windows, subprocess.Popen.terminate gọi số TerminalProcess của win32. Tuy nhiên, hành vi tôi thấy là quá trình con của quá trình tôi đang cố gắng chấm dứt vẫn đang chạy. Tại sao vậy? Làm thế nào để đảm bảo tất cả các tiến trình con bắt đầu bởi quá trình này bị giết?quy trình con: xóa quy trình con trong Windows

+0

Phiên bản nào của Python và Windows? –

+0

Dưới đây là 2 tùy chọn 1. Sử dụng exe này như là một tiến trình con mà giết chết các cây xử lý cho bạn: http://www.latenighthacking.com/projects/2002/kill/ 2. Chuyển đổi mã C sau sang Python với ctypes: http: //stackoverflow.com/questions/1173342/terminate-a-process-tree-c-for-windows – Unknown

Trả lời

49

Bằng cách sử dụng 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) 
+1

Mã đó trông giống như nó sẽ chỉ giết trẻ em cấp đầu tiên, không phải cháu, vv Có thể là một vấn đề nếu bạn đang khởi chạy công cụ xây dựng hoặc .bat/.cmd tệp với cmd.exe.Trừ khi get_children() có nghĩa là cháu quá? – Macke

+1

Chính xác. Để bao gồm các cháu, bạn nên chỉ định tùy chọn 'đệ quy' như trong parent.get_children (recursive = True) –

+5

Đây là câu trả lời cũ, nhưng đó là chính xác những gì tôi đang tìm kiếm - một cách đa nền tảng để giết tất cả các tiến trình con. Tất cả các câu trả lời khác xuất hiện trên Google đều không thể thực hiện được. Cảm ơn bạn đã cho psutil! – Gilead

7

Đây là một việc khó làm. Windows không thực sự lưu trữ một cây xử lý trong không gian tiến trình. Cũng không thể chấm dứt một quá trình và chỉ ra rằng đó là trẻ em cũng nên chết.

Một cách xung quanh đó là sử dụng taskkill và yêu cầu nó chặn toàn bộ cây.

Một cách khác để làm điều đó (giả sử rằng bạn đang đẻ trứng quá trình cấp cao nhất) là sử dụng một mô-đun đã được phát triển với các loại điều này trong tâm trí: http://benjamin.smedbergs.us/blog/tag/killableprocess/

Để làm được điều này quát cho chính mình , bạn phải dành thời gian xây dựng danh sách ngược. Đó là, một quá trình lưu trữ con trỏ đến PARENT của nó, nhưng cha mẹ dường như không lưu trữ thông tin về trẻ em.

Vì vậy, bạn phải xem xét tất cả các quy trình trong hệ thống (thực sự không khó), sau đó tự kết nối các dấu chấm bằng cách xem trường quy trình gốc. Sau đó, bạn chọn cây bạn quan tâm và đi bộ toàn bộ điều, giết chết từng nút lần lượt từng cái một.

Lưu ý rằng Windows không cập nhật con trỏ mẹ của con khi cha mẹ chết, vì vậy có thể có khoảng trống trong cây của bạn. Tôi không biết bất cứ điều gì bạn có thể làm về những điều đó.

6

Đặt trẻ em trong một NT Job object, sau đó bạn có thể giết chết tất cả trẻ em

+3

Các đối tượng công việc có vẻ đúng cách để tiếp cận vấn đề này; quá tệ đến nỗi điều này không được tích hợp với mô-đun subprocess. –

27

Sử dụng taskkill với /T cờ

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

Cờ để taskkill có các tài liệu sau:

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. 

Hoặc đi bộ cây quá trình sử dụng comtypes và 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) 
+0

Cảm ơn bạn vì điều này. – Speakeasys

6

Dưới đây là ví dụ mã cho phương pháp đối tượng công việc, nhưng thay vì subprocess nó sử dụng 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) 
+0

+1: có vẻ như giải pháp mạnh mẽ nhất hoạt động ngay cả khi quá trình gốc bị lỗi. Đây là [giải thích về cách nó hoạt động] (http://stackoverflow.com/a/23587108/4279) – jfs

3

tôi đã cùng một vấn đề và chỉ cần giết quá trình qua lệnh cửa sổ với tùy chọn giết trẻ em "/ 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) 
+0

Tôi đã cố gắng để giết một quá trình xây dựng Gradle bắt đầu với 'subprocess.Popen()'. Một 'process.terminate()' hay 'process.kill()' đơn giản không hoạt động trên WIndows 7, và cả tùy chọn 'psutils' ở trên, nhưng điều này đã làm. –

Các vấn đề liên quan