2017-09-13 5 views
3

파이썬 타이머를 트리거하여 서브 프로세스를 생성하는 프로그램이있다. 이러한 서브 프로세스는 프로그램이 종료되거나 종료되면 종료되어야합니다. 그렇게하기 위해, 나는 부모가 죽으면 어떤 신호를 받아야 하는지를 설정하는 "prctl hack"을 사용하고있다. 내가 얻는 바라지 않는 행동은 : 나의 주요 과정이 돌아가고 있지만, 아이들은 죽임을 당한다. 당신은 스레드가 죽기 전에 sleep 프로세스가 계속 실행, 즉를 알 수쓰레드가 죽을 때 서브 프로세스가 죽는다

from threading import Timer 
import time 
import os 
import subprocess 
import ctypes 
import signal 

def set_pdeathsig(): 
     print("child PID: %d" % os.getpid()) 
     print("child's parent PID: %d" % os.getppid()) 
     prctl = ctypes.CDLL("libc.so.6").prctl 
     PR_SET_PDEATHSIG = 1 
     prctl(PR_SET_PDEATHSIG, signal.SIGTERM) 

def thread1(): 
     subprocess.Popen(['sleep', 'infinity'], preexec_fn=set_pdeathsig) 
     time.sleep(10) 
     print("thread 1 finished") 

def thread2(): 
     subprocess.Popen(['sleep', 'infinity'], preexec_fn=set_pdeathsig) 
     time.sleep(10) 
     print("thread 2 finished") 

print("main thread PID: %d" % os.getpid()) 

t1 = Timer(1, thread1) 
t2 = Timer(1, thread2) 

t1.start() 
t2.start() 

time.sleep(100) 

: 다음 코드는 문제를 다시 만듭니다. 타이머 스레드가 종료 된 후에도 주 스레드가 활성 상태 인 경우에도 해당 하위 프로세스가 종료됩니다.

+0

분명히 당신은'os.setpgid' 함수를 호출하지 않습니다. –

+0

감사합니다 @TheophileDano, 그것은 이전 테스트의 코드 일뿐입니다. 거기 있으면 안된다. 제거하면 문제가 계속 발생합니다. –

답변

1

이것은 예상하고 문서화 된 동작입니다. prctl (2)의 매뉴얼 페이지에서 :

 Warning: the "parent" in this case is considered to be the 
     thread that created this process. In other words, the signal 
     will be sent when that thread terminates (via, for example, 
     pthread_exit(3)), rather than after all of the threads in the 
     parent process terminate. 

즉, 다른 프로세스를 생성해야합니다. 종료 한 스레드에서이 작업을 수행하면 예상대로 하위 프로세스가 종료되고이를 처리 할 방법이 없습니다.

다른 스레드를 추가하고 거기에서 시작하는 프로세스를 수행합니다. 이 작업과 같은 것이 있습니까 :

from threading import Timer 
from threading import Thread 
import queue 
import time 
import os 
import subprocess 
import ctypes 
import signal 

def set_pdeathsig(): 
    print("child PID: %d" % os.getpid()) 
    print("child's parent PID: %d" % os.getppid()) 
    prctl = ctypes.CDLL("libc.so.6").prctl 
    PR_SET_PDEATHSIG = 1 
    prctl(PR_SET_PDEATHSIG, signal.SIGTERM) 

def thread1(q): 
    q.put(["sleep", "infinity"]) 
    time.sleep(5) 
    print("thread 1 finished") 

def thread2(q): 
    q.put(["sleep", "infinity"]) 
    time.sleep(5) 
    print("thread 2 finished") 

def process_manager(q): 
    while True: 
     foo = q.get() 
     subprocess.Popen(foo, preexec_fn=set_pdeathsig) 

print("main thread PID: %d" % os.getpid()) 

qu = queue.Queue() 
pm_thread = Thread(group=None, target=process_manager, args=(qu,)) 
pm_thread.daemon = True 
pm_thread.start() 


t1 = Timer(1, thread1, args=(qu,)) 
t2 = Timer(1, thread2, args=(qu,)) 

t1.start() 
t2.start() 

time.sleep(15) 

이것은 원하는 작업을 수행합니다 (Python3.5는 테스트에 사용됨). 물론 오케스트레이션 스레드가 적합하지 않은 이유가있을 수 있지만 어쨌든 솔루션 후보로 제공합니다. 이제 하위 프로세스는 Timer 스레드가 종료 된 후에도 그대로 유지되지만 주 스레드가 종료되면 여전히 종료됩니다.