Domanda

Ho letto da qualche parte che fa eccezione KeyboardInterrupt viene generato solo nel thread principale in Python. Ho anche letto che il thread principale è bloccata, mentre l'esecuzione della filettatura bambino. Quindi, questo significa che CTRL + C non potrà mai raggiungere il thread figlio. Ho provato il seguente codice:

def main():
    try:
        thread = threading.Thread(target=f)
        thread.start()  # thread is totally blocking (e.g., while True)
        thread.join()
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        sys.exit(1)

def f():
    while True:
        pass  # do the actual work

In questo caso non v'è alcun effetto di CTRL + C sull'esecuzione. E 'come se non è in grado di ascoltare il segnale. Sto capendo questo modo sbagliato? C'è un altro modo per uccidere il filo con CTRL + C ?

È stato utile?

Soluzione

Il problema è che si sta utilizzando thread1.join(), che farà sì che il vostro programma di aspettare fino a che termina di filo per continuare.

I segnali sarà sempre catturato dal processo principale, perché è quello che riceve i segnali, è il processo che ha filetti.

Farlo come si mostra, si sono fondamentalmente esegue un'applicazione 'normale', senza le funzioni di filo, come si avvia 1 filo e attendere fino a quando finisce per continuare.

Altri suggerimenti

Se si desidera avere thread principale per ricevere il CTRL + C segnale, mentre l'adesione, può essere fatto con l'aggiunta di timeout di chiamata join().

Di seguito sembra funzionare (non dimenticare di aggiungere daemon=True se si vuole principale di porre fine in realtà):

thread1.start()
while True:
    thread1.join(600)
    if not thread1.isAlive():
        break

In Python, è vero che le eccezioni KeyboardInterrupt sono sollevate solo nel thread principale di ciascun processo. Ma, come altre risposte menzionate, è anche vero che i blocchi Thread.join metodo il thread chiamante, tra cui KeyboardInterrupt eccezioni . Ecco perché Ctrl + C sembra avere alcun effetto. All'esecuzione principali resti filo bloccati alla linea thread.join()

Quindi, una soluzione semplice per la tua domanda è quello in primo luogo, aggiungere un argomento timeout per thread.join() e mettere quella chiamata in un ciclo che termina quando il thread bambino, in modo che le eccezioni KeyboardInterrupt possono essere formulati dopo ogni timeout, e in secondo luogo, rendono il thread figlio demoniaco , il che significa che il suo padre (il thread principale qui) ucciderà quando esce (solo le discussioni non-daemon non vengono uccisi, ma uniti quando le loro uscite genitore):

def main():
    try:
        thread = threading.Thread(target=f, daemon=True)  # create a daemon child thread
        thread.start()

        while thread.is_alive():
            thread.join(1)  # join shortly to not block KeyboardInterrupt exceptions
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        sys.exit(1)

def f():
    while True:
        pass  # do the actual work

Ma una soluzione migliore, se controlli il codice del thread figlio, è quello di informare il thread figlio per uscire con garbo (invece che di colpo come con la prima soluzione), per esempio con un threading.Event:

def main():
    try:
        event = threading.Event()
        thread = threading.Thread(target=f, args=(event,))
        thread.start()
        event.wait()  # wait forever but without blocking KeyboardInterrupt exceptions
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        event.set()  # inform the child thread that it should exit
        sys.exit(1)

def f(event):
    while not event.is_set():
        pass  # do the actual work
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top