복붙노트

[PYTHON] 파이썬 : 부모 프로세스가 죽으면 어떻게 자식 프로세스를 죽일 수 있습니까?)

PYTHON

파이썬 : 부모 프로세스가 죽으면 어떻게 자식 프로세스를 죽일 수 있습니까?)

자식 프로세스가 시작됩니다.

subprocess.Popen(arg)

부모가 비정상적으로 종료 될 때 죽는 것을 보장 할 수있는 방법이 있습니까? Windows와 Linux에서 모두 작동해야합니다. Linux 용 솔루션에 대해 알고 있습니다.

편집하다:

프로세스를 시작하는 다른 방법을 사용하여 솔루션이 존재하는 경우 하위 프로세스로 하위 프로세스 시작 요구 사항을 완화 할 수 있습니다.

해결법

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

    1.Heh, 나는 단지 이것을 나 자신으로 어제 연구하고 있었다! 자녀 프로그램을 변경할 수 없다고 가정합니다.

    Heh, 나는 단지 이것을 나 자신으로 어제 연구하고 있었다! 자녀 프로그램을 변경할 수 없다고 가정합니다.

    리눅스에서는 prctl (PR_SET_PDEATHSIG, ...)만이 유일하게 신뢰할 수있는 선택 일 것이다. (만약 자식 프로세스가 반드시 죽어야한다면, SIGTERM 대신에 SIGKILL로 시그널을 설정하는 것이 좋을 것이다. 링크 된 코드는 SIGTERM을 사용하지만 자식은 원하는 경우 SIGTERM을 무시할 수있는 옵션을 가지고있다. )

    Windows에서 가장 신뢰할 수있는 옵션은 Job 객체를 사용하는 것입니다. 아이디어는 "작업"(프로세스의 컨테이너 종류)을 만든 다음 하위 프로세스를 작업에 배치하고 "아무도이 작업에 '핸들'을 보유하지 않을 때 마법 옵션을 설정한다는 것입니다 그런 다음 그 안에있는 프로세스를 종료하십시오. " 기본적으로 작업에 대한 유일한 '처리'는 상위 프로세스가 보유하고있는 프로세스이며, 상위 프로세스가 종료되면 OS는 모든 핸들을 닫고 그 다음에 열린 핸들이 없다는 것을 알게됩니다 작업. 그러면 요청에 따라 자식을 죽입니다. (자식 프로세스가 여러 개인 경우 모두 동일한 작업에 할당 할 수 있습니다.)이 응답에는 win32api 모듈을 사용하여이를 수행하는 샘플 코드가 있습니다. 이 코드는 Subprocess.Popen 대신 CreateProcess를 사용하여 자식을 시작합니다. 그 이유는 생성 된 자식에 대해 "프로세스 핸들"을 가져와야하기 때문에 CreateProcess는 기본적으로이를 반환합니다. subprocess.Popen을 오히려 사용하고 싶다면, 그 대답에서 Subprocess.Popen과 OpenProcess를 사용하는 코드의 (테스트받지 않은) 사본을 CreateProcess 대신 사용하십시오 :

    import subprocess
    import win32api
    import win32con
    import win32job
    
    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)
    
    child = subprocess.Popen(...)
    # Convert process id to process handle:
    perms = win32con.PROCESS_TERMINATE | win32con.PROCESS_SET_QUOTA
    hProcess = win32api.OpenProcess(perms, False, child.pid)
    
    win32job.AssignProcessToJobObject(hJob, hProcess)
    

    엄밀히 말하면, Popen과 OpenProcess 호출 사이에서 아이가 죽는 경우 작은 경쟁 조건이 있습니다. 걱정할 것인지 결정할 수 있습니다.

    작업 개체를 사용할 때의 한 가지 단점은 Vista 또는 Win7에서 실행할 때 프로그램이 Windows 셸에서 (즉, 아이콘을 클릭하여) 실행되면 작업 개체가 이미 할당되어 있고 새 작업 개체가 실패합니다. Win8은 이것을 수정합니다 (작업 개체를 중첩 할 수있게 함). 또는 명령 줄에서 프로그램을 실행하면 문제가 없습니다.

    자식을 수정할 수 있다면 (예 : 다중 처리를 사용할 때와 같이) 가장 좋은 방법은 부모의 PID를 자식에게 전달하는 것입니다 (예 : 명령 줄 인수 또는 args = multiprocessing.Process 인수). 그리고:

    POSIX에서 : os.getppid ()를 가끔씩 호출하는 자식에 스레드를 생성하십시오. 반환 값이 부모로부터 전달 된 pid와 일치하지 않으면 os._exit ()를 호출하십시오. (이 접근법은 OS X을 포함한 모든 유닉스에 이식 가능하지만 prctl 트릭은 리눅스에만 한정되어있다.)

    Windows의 경우 : OpenProcess 및 os.waitpid를 사용하는 하위 스레드를 생성합니다. ctypes 사용 예제 :

    from ctypes import WinDLL, WinError
    from ctypes.wintypes import DWORD, BOOL, HANDLE
    # Magic value from http://msdn.microsoft.com/en-us/library/ms684880.aspx
    SYNCHRONIZE = 0x00100000
    kernel32 = WinDLL("kernel32.dll")
    kernel32.OpenProcess.argtypes = (DWORD, BOOL, DWORD)
    kernel32.OpenProcess.restype = HANDLE
    parent_handle = kernel32.OpenProcess(SYNCHRONIZE, False, parent_pid)
    # Block until parent exits
    os.waitpid(parent_handle, 0)
    os._exit(0)
    

    이렇게하면 내가 언급 한 작업 개체의 가능한 문제를 피할 수 있습니다.

    정말 확실하게 알고 싶다면이 모든 솔루션을 결합 할 수 있습니다.

    희망이 도움이됩니다!

  2. ==============================

    2.Popen 객체는 terminate 및 kill 메소드를 제공합니다.

    Popen 객체는 terminate 및 kill 메소드를 제공합니다.

    https://docs.python.org/2/library/subprocess.html#subprocess.Popen.terminate

    이것들은 당신을 위해 SIGTERM과 SIGKILL 시그널을 보낸다. 아래와 비슷한 것을 할 수 있습니다 :

    from subprocess import Popen
    
    p = None
    try:
        p = Popen(arg)
        # some code here
    except Exception as ex:
        print 'Parent program has exited with the below error:\n{0}'.format(ex)
        if p:
            p.terminate()
    

    최신 정보:

    당신은 맞습니다 - 위의 코드는 하드 충돌이나 프로세스를 죽이는 사람을 보호하지 못합니다. 이 경우 클래스에서 하위 프로세스를 래핑하고 폴링 모델을 사용하여 부모 프로세스를 볼 수 있습니다. psutil은 비표준임을 유의하십시오.

    import os
    import psutil
    
    from multiprocessing import Process
    from time import sleep
    
    
    class MyProcessAbstraction(object):
        def __init__(self, parent_pid, command):
            """
            @type parent_pid: int
            @type command: str
            """
            self._child = None
            self._cmd = command
            self._parent = psutil.Process(pid=parent_pid)
    
        def run_child(self):
            """
            Start a child process by running self._cmd. 
            Wait until the parent process (self._parent) has died, then kill the 
            child.
            """
            print '---- Running command: "%s" ----' % self._cmd
            self._child = psutil.Popen(self._cmd)
            try:
                while self._parent.status == psutil.STATUS_RUNNING:
                    sleep(1)
            except psutil.NoSuchProcess:
                pass
            finally:
                print '---- Terminating child PID %s ----' % self._child.pid
                self._child.terminate()
    
    
    if __name__ == "__main__":
        parent = os.getpid()
        child = MyProcessAbstraction(parent, 'ping -t localhost')
        child_proc = Process(target=child.run_child)
        child_proc.daemon = True
        child_proc.start()
    
        print '---- Try killing PID: %s ----' % parent
        while True:
            sleep(1)
    

    이 예제에서는 영원히 실행될 '핑 -t 로컬 호스트'b / c를 실행합니다. 상위 프로세스를 종료하면 하위 프로세스 (ping 명령)도 종료됩니다.

  3. from https://stackoverflow.com/questions/23434842/python-how-to-kill-child-processes-when-parent-dies by cc-by-sa and MIT license