Ctrl-C cioè KeyboardInterrupt per uccidere i thread in Python

Ho letto da qualche parte che KeyboardInterrupt eccezione è aumentato solo nel thread principale in Python. Ho anche letto che il thread principale è bloccato mentre il bambino thread esegue. Questo significa che CTRL+C non può mai raggiungere il bambino thread. 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 vi è alcun effetto di CTRL+C sull’esecuzione. È come non è in grado di ascoltare il segnale. Sono io la comprensione di questo modo sbagliato? C’è qualche altro modo per uccidere il thread utilizzando CTRL+C?

  • Vedere stackoverflow.com/questions/323972/…
  • Il thread principale non è bloccato perché iniziare un altro thread. Quale sarebbe il punto del thread, se questo fosse vero? È perché si sta chiamando thread1.join(), che FA un blocco fino a quando thread1 è fatto.
InformationsquelleAutor Amit S | 2010-11-09



3 Replies
  1. 10

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

    I segnali saranno sempre catturato dal processo principale, perché è quello che riceve i segnali, è il processo che si è thread.

    Farlo come si mostra, si sono fondamentalmente l’esecuzione di un ‘normale’ applicazione, senza filettatura caratteristiche, come si inizia a 1 thread e aspettare fino a quando non finisce per continuare.

  2. 13

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

    Il seguente sembra essere al lavoro (non dimenticare di aggiungere daemon=True se vuoi principale è in realtà alla fine):

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

    In Python, è vero che KeyboardInterrupt eccezioni sollevate solo nel thread principale di ogni processo. Ma come altre risposte indicate, è anche vero che il metodo Thread.join blocca il thread chiamante, tra KeyboardInterrupt eccezioni. Che è il motivo per cui Ctrl+C sembra non avere effetto: l’esecuzione nel thread principale rimane bloccato sulla linea thread.join().

    Così una semplice soluzione per la tua domanda, in primo luogo, aggiungere un timeout argomento per thread.join() e mettere la chiamata in un ciclo che termina quando il bambino thread viene chiuso, in modo che KeyboardInterrupt eccezioni che possono essere sollevate dopo ogni timeout, e in secondo luogo, fare il bambino thread demoniaca, il che significa che i suoi genitori (il thread principale qui) ucciderà quando esce (non solo daemon thread non vengono uccisi, ma entra quando il genitore uscite):

    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 è possibile controllare il bambino thread del codice, è quello di informare il bambino thread uscire con grazia (anziché bruscamente 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

Lascia un commento