¿Cómo terminar un hilo cuando finaliza el programa principal?

Respuestas:

46

Marque esta pregunta. La respuesta correcta tiene una gran explicación sobre cómo terminar los hilos de la manera correcta: ¿Hay alguna forma de eliminar un hilo en Python?

Para hacer que el hilo se detenga en la señal de interrupción del teclado (ctrl + c), puede detectar la excepción "KeyboardInterrupt" y limpiar antes de salir. Me gusta esto:

try:
    start_thread()  
except (KeyboardInterrupt, SystemExit):
    cleanup_stop_thread()
    sys.exit()

De esta forma, puede controlar qué hacer cuando el programa finaliza abruptamente.

También puede utilizar el módulo de señal incorporado que le permite configurar controladores de señal (en su caso específico, la señal SIGINT): http://docs.python.org/library/signal.html

rogeriopvl
fuente
Muchas gracias por tu respuesta. Puede que no haya planteado la pregunta correctamente. En el ejemplo dado en esa pregunta, todavía era necesario ejecutar la función stop () del hilo. Cuando finalizo un programa de forma anormal con ctrl + C, eso no puede suceder. Entonces, mi pregunta es un poco como, "¿cómo llamo a la función mythread.stop () si se interrumpe el flujo del hilo principal?"
facha
1
¿Es cleanup_stop_thread()una función global que puedo usar? ¿O debería tener que implementarlo?
alper
@alper, creo que tal vez fue solo un ejemplo de que es posible implementar algo. Deberías implementar eso
Leonardo Rick
98

Si hace que sus subprocesos de trabajo sean subprocesos de demonio, estos morirán cuando todos los subprocesos que no son demonios (por ejemplo, el subproceso principal) hayan salido.

http://docs.python.org/library/threading.html#threading.Thread.daemon

ʇsәɹoɈ
fuente
4
Gracias por la respuesta simple y precisa, el subproceso predeterminado. El estado del demonio de subprocesos isDaemon()es Falso, configúrelo como Verdadero por setDaemon(True).
Tong
3
Esto responde a la pregunta y simplemente funciona. La operación no preguntó cómo salir de los hilos limpiamente en general.
Johannes Overmann
1
isDaemon()y setDaemon()son viejos getters / setters (según el documento vinculado arriba), solo use daemon=Trueenthreading.Thread()
fabio.sang
1
Tenga en cuenta que el uso de subprocesos de demonio puede causar otros problemas y probablemente no sea lo que desea aquí: stackoverflow.com/questions/20596918/…
Doopy
Para evitar el uso de subprocesos de demonio y eliminarlos de forma limpia, consulte stackoverflow.com/questions/58910372/…
Pat-Laugh
14

Intente habilitar el subproceso como daemon-thread.

Por ejemplo:

Recomendado:

from threading import Thread

t = Thread(target=<your-method>)
t.daemon = True  # This thread dies when main thread (only non-daemon thread) exits.
t.start()

En línea:

t = Thread(target=<your-method>, daemon=True).start()

API antigua:

t.setDaemon(True)
t.start()

Cuando su hilo principal termina ("es decir, cuando presiono Ctrl+ C"), las instrucciones anteriores también eliminarán otros hilos.

Benyamin Jafari
fuente
1
Tenga en cuenta que el uso de subprocesos daemon puede causar otros problemas y probablemente no sean lo que desea aquí: stackoverflow.com/questions/20596918/…
Doopy
12

Utilice el módulo atexit de la biblioteca estándar de Python para registrar funciones de "terminación" que se llaman (en el hilo principal) en cualquier terminación razonablemente "limpia" del hilo principal, incluida una excepción no detectada como KeyboardInterrupt. Tales funciones de terminación pueden (¡aunque inevitablemente en el hilo principal!) Llamar a cualquier stopfunción que necesite; junto con la posibilidad de configurar un hilo como daemon, que te brinda las herramientas para diseñar adecuadamente la funcionalidad del sistema que necesitas.

Alex Martelli
fuente
Tenga en cuenta que este enfoque funcionó sin requerir subprocesos demonizados en versiones de Python anteriores a 2.6.5, consulte la respuesta a stackoverflow.com/questions/3713360/… . Esto es desafortunado en mi humilde opinión, ya que los hilos del demonio durante el apagado son un poco desordenados antes de Python 3.4 ( bugs.python.org/issue19466 ). Si detiene y une sus subprocesos daemon en sus controladores atexit, todo debería estar bien, con el costo (probablemente insignificante) de serializar su eliminación de subprocesos.
NeilenMarais
Tenga en cuenta que pueden suceder cosas raras debido a las atexit.register()llamadas pospuestas en los módulos de Python, lo que hace que su procedimiento de terminación se ejecute después del de multiprocessing. Corro en este trato con el problema Queuey daemonlas discusiones: “error EOF” al salir del programa utilizando multiprocesamiento cola e hilo .
Delgan
Aparentemente, en las versiones modernas de Python, como 3.7.4+, los atexitcontroladores no se llaman cuando los subprocesos que no son demonios están activos y el subproceso principal sale. Consulte Secuencia de comandos atascada al salir cuando se usa atexit para terminar subprocesos .
martineau
9

Si genera un hilo como myThread = Thread(target = function)ese, y luego hágalo myThread.start(); myThread.join(). Cuando se inicia CTRL-C, el hilo principal no sale porque está esperando esa myThread.join()llamada de bloqueo . Para solucionar esto, simplemente ponga un tiempo de espera en la llamada .join (). El tiempo de espera puede ser tan largo como desee. Si desea que espere indefinidamente, coloque un tiempo de espera realmente largo, como 99999. También es una buena práctica hacerlo myThread.daemon = Truepara que todos los subprocesos salgan cuando sale el subproceso principal (que no es un demonio).

Milean
fuente
myThread.daemon = Truees una maravillosa solución a este problema.
Brannon
5
@Brannon no .daemon=Trueestá en una solución sólida. Consulte este hilo para obtener una explicación: stackoverflow.com/a/20598791/5562492
Odyssee
2

Los subprocesos de Daemon se eliminan sin gracia, por lo que las instrucciones del finalizador no se ejecutan. Una posible solución es verificar si el hilo principal está vivo en lugar de un bucle infinito.

Por ejemplo, para Python 3:

while threading.main_thread().isAlive():
    do.you.subthread.thing()
gracefully.close.the.thread()

Consulte Comprobar si el subproceso principal sigue activo desde otro subproceso .

umi
fuente