2014-10-16 2 views
9

Ho un processo Python che genera altri 5 processi Python usando il modulo multiprocessing. Chiamiamo il processo genitore P0 e gli altri P1-P5. Il requisito è, se inviamo un SIGTERM a P0, dovrebbe prima spegnere P1 a P5 e poi uscire da solo.In che modo un processo Python si chiude in modo elegante dopo aver ricevuto SIGTERM mentre era in attesa su un semaforo?

Il fermo P1 e P5 sono in attesa sui semafori. Quindi quando invio SIGTERM a questi processi, invocano il gestore di segnale e escono. Ma dal momento che stanno aspettando il semaforo, lanciano un'eccezione. C'è un modo per catturare quell'eccezione prima di uscire, in modo che P0 a P5 possa fare un'uscita graduale?

Traceback:

Traceback (most recent call last): 
    File "/usr/lib64/python2.7/multiprocessing/process.py", line 258, in _bootstrap 
Traceback (most recent call last): 
Process Process-2: 
    File "/usr/lib64/python2.7/multiprocessing/process.py", line 258, in _bootstrap 
Traceback (most recent call last): 
self.run() 
File "/usr/lib64/python2.7/multiprocessing/process.py", line 114, in run 
self._target(*self._args, **self._kwargs) 
Process Process-5: 
Traceback (most recent call last): 
File "/usr/lib64/python2.7/multiprocessing/process.py", line 258, in _bootstrap 
    self.run() 
File "/usr/lib64/python2.7/multiprocessing/process.py", line 114, in run 
    self._target(*self._args, **self._kwargs) 
File "/opt/fireeye/scripts/mip/StaticAnalysisRunner.py", line 45, in run 
    qsem.acquire() 
+0

Quale versione di Python stai usando? Quale chiamata specifica P1 e P5 stanno effettivamente facendo in modo che siano in attesa su un semaforo? Puoi includere i tracebacks? – dano

+1

Un esempio di codice minimale che riproduce il tuo problema sarebbe fantastico. –

+0

Sto usando Python 2.7.8 P1 a P5 stanno cercando di accedere a una coda condivisa attraverso i processi e l'accesso alla coda è protetto utilizzando un semaphore.Something come questo: sem.acquire() item = q.get() sem.release() –

risposta

13

È possibile installare un gestore di segnale, che genera un'eccezione che viene poi catturato nel sottoprocesso per gestire le uscite con grazia.

Ecco un esempio di uno script che attende in un semaforo in un sottoprocesso e termina con grazia quando inviato un SIGTERM.

#!/usr/bin/env python 

import signal 
import time 
import multiprocessing 

class GracefulExit(Exception): 
    pass 


def signal_handler(signum, frame): 
    raise GracefulExit() 


def subprocess_function(): 
    try: 
     sem = multiprocessing.Semaphore() 
     print "Acquiring semaphore" 
     sem.acquire() 
     print "Semaphore acquired" 

     print "Blocking on semaphore - waiting for SIGTERM" 
     sem.acquire() 
    except GracefulExit: 
     print "Subprocess exiting gracefully" 


if __name__ == "__main__": 

    # Use signal handler to throw exception which can be caught to allow 
    # graceful exit. 
    signal.signal(signal.SIGTERM, signal_handler) 

    # Start a subprocess and wait for it to terminate. 
    p = multiprocessing.Process(target=subprocess_function) 
    p.start() 

    print "Subprocess pid: %d" % p.pid 

    p.join() 

Un esempio di esecuzione di questo script è il seguente:

$ ./test.py 
Subprocess pid: 7546 
Acquiring semaphore 
Semaphore acquired 
Blocking on semaphore - waiting for SIGTERM 
----> Use another shell to kill -TERM 7546 
Subprocess exiting gracefully 

Non c'è traceback dal sottoprocesso e il flusso che mostra le uscite di processo parziali in maniera graziosa. Questo perché SIGTERM viene catturato dal gestore di segnali di sottoprocesso che lancia una normale eccezione Python che può essere gestita all'interno del processo.