2010-06-23 9 views
14

Ho un demone Python con thread. Come ogni buon daemon, vuole lanciare tutti i suoi thread di lavoro, quindi attendere fino a quando non viene detto di terminare. Il normale segnale di terminazione è SIGTERM, e nella maggior parte delle lingue mi piacerebbe terminare aspettando un evento o un mutex, quindi usare il threading.Event aveva senso per me. Il problema è che gli oggetti Event e i segnali Unix di Python non sembrano funzionare bene insieme.Perché utilizzare il threading. Il risultato dell'evento in SIGTERM non viene rilevato?

Questo funziona come previsto, con scadenza SIGTERM:

import signal 
import time 

RUN = True 

def handle(a, b): 
    global RUN 
    print "handled" 
    RUN = False 

signal.signal(signal.SIGTERM, handle) 
while RUN: 
    time.sleep(0.250) 
print "Stopping" 

ma questo si traduce in nessun SIGTERM essere consegnato (vale a dire, a parte smettere, "gestito" non viene stampato):

import signal 
import threading 

RUN_EVENT = threading.Event() 

def handle(a, b): 
    print "handled" 
    RUN_EVENT.set() 

signal.signal(signal.SIGTERM, handle) 
RUN_EVENT.wait() 
print "Stopping" 

Quindi la mia domanda è:

  1. Sto abusando di threading.Event in qualche modo?
  2. Se non lo sono, esiste un'alternativa diversa dal meccanismo di polling e sospensione del primo esempio?
  3. Anche se non lo sono, perché utilizzare threading.Event uccidere il gestore di segnale?

risposta

13

Da Python documentation on signals:

Sebbene Python gestori dei segnali vengono chiamati in modo asincrono per quanto riguarda l'utente Python è interessato, possono avvenire solo tra le istruzioni “Atomic” dell'interprete Python. Ciò significa che i segnali che arrivano durante lunghi calcoli implementati esclusivamente in C (come le corrispondenze di espressioni regolari su grandi corpi di testo) possono essere ritardati per una quantità arbitraria di tempo.

ho provato vari threading e thread classi e nessuno di loro lavorano nel modo desiderato - questo è probabilmente a causa di come Python gestisce segnali.

In signal, tuttavia, è presente una funzione pause() che viene interrotta fino a quando non viene ricevuto un segnale dal processo. Il tuo esempio modificato sarebbe il seguente:

import signal 

RUN = True 

def handle(a, b): 
    global RUN 
    print "handled" 
    RUN = False 

signal.signal(signal.SIGTERM, handle) 
while RUN: 
    signal.pause() 
print "Stopping" 

Ho controllato su Linux, funziona. Non penso che si possa classificare come poll-and-sleep più se la tua applicazione non usa molti altri segnali.

+0

Funzione fastidiosa di Python, ma soluzione perfetta. Grazie. Confesserò che non mi è venuto in mente di cercare ulteriori restrizioni sull'uso del segnale, poiché sapevo che l'equivalente C avrebbe funzionato perfettamente. –

+3

Questo significa che l'unico modo per gestire i segnali è di dedicare il thread principale (genitore) ai segnali di acquisizione (bloccando su 'signal.pause()')? Ciò che questo implica è che il thread principale non può più fare nulla di utile. In altre parole, non è possibile avere un modello master/worker (dove i 2 thread parlano tra loro) ma è necessario un modello master/worker + worker (dove i 2 worker parlano tra loro e il master non fa nulla. –

Problemi correlati