2017-09-13 68 views
3

我有一个程序触发Python定时器来产生子进程。一旦我的程序被终止或终止,这些子进程应该被终止。为了做到这一点,我使用了“prctl hack”,它设置了一旦其父母死亡,孩子应该接收哪个信号。我得到的不良行为是:即使我的主要过程正在运行,孩子们也会被杀死。下面的代码重现该问题:线程死时子进程死掉

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) 

你可以注意到,线程死之前,该sleep进程仍在运行。计时器线程死后,其各个子进程也会死掉,即使主线程还活着。

+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用于测试)。当然,编排线程可能会有些不合适的原因,但无论如何我都会提供它作为解决方案候选。现在你的子进程在计时器线程中死掉了,但是当你的主线程退出时它仍然会被终止。