2017-09-13 111 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用於測試)。當然,編排線程可能會有些不合適的原因,但無論如何我都會提供它作爲解決方案候選。現在你的子進程在計時器線程中死掉了,但是當你的主線程退出時它仍然會被終止。