Como encerrar um thread quando o programa principal termina?

86

Se eu tiver um thread em um loop infinito, há uma maneira de encerrá-lo quando o programa principal terminar (por exemplo, quando pressiono Ctrl+ C)?

facha
fonte

Respostas:

46

Verifique esta questão. A resposta correta tem uma ótima explicação sobre como encerrar threads da maneira certa: Existe alguma maneira de eliminar um Thread em Python?

Para fazer o thread parar no sinal de interrupção de teclado (ctrl + c), você pode capturar a exceção "KeyboardInterrupt" e limpar antes de sair. Como isso:

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

Desta forma, você pode controlar o que fazer sempre que o programa for encerrado abruptamente.

Você também pode usar o módulo de sinal integrado que permite configurar manipuladores de sinal (no seu caso específico, o sinal SIGINT): http://docs.python.org/library/signal.html

rogeriopvl
fonte
Muito obrigado pela sua resposta. Posso não ter formulado a pergunta corretamente. No exemplo dado nessa questão, ainda era necessário executar a função stop () da thread. Quando eu termino um programa de forma anormal com ctrl + C, isso não pode acontecer. Então, minha pergunta é um pouco como, "como faço para chamar a função mythread.stop () se o fluxo do thread principal for interrompido"
facha 01 de
1
É cleanup_stop_thread()uma função global que posso usar? ou devo implementá-lo?
final de
@alper, acho que talvez tenha sido apenas um exemplo de que é possível implementar algo. Você deve implementar isso
Leonardo Rick
100

Se você criar threads daemon de threads de trabalho, elas morrerão quando todas as threads não-daemon (por exemplo, a thread principal) forem encerradas.

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

ʇsәɹoɈ
fonte
4
Obrigado pela resposta simples e precisa, o threading padrão. O status do daemon de thread isDaemon()é False, defina-o como True por setDaemon(True).
Tong
3
Isso responde à pergunta e simplesmente funciona. O op não perguntou como sair de tópicos de forma limpa em geral.
Johannes Overmann
1
isDaemon()e setDaemon()são getters / setters antigos (conforme o documento vinculado acima), basta usar daemon=Trueinthreading.Thread()
fabio.sang
1
Observe que o uso de threads daemon pode causar outros problemas e provavelmente não é o que você quer aqui: stackoverflow.com/questions/20596918/…
Doopy
Para evitar o uso de threads daemon e eliminar threads de forma limpa, consulte stackoverflow.com/questions/58910372/…
usuário
15

Tente habilitar o sub-thread como daemon-thread.

Por exemplo:

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()

Na linha:

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

API antiga:

t.setDaemon(True)
t.start()

Quando seu thread principal termina ("isto é, quando eu pressiono Ctrl+ C"), outros threads também serão encerrados pelas instruções acima.

Benyamin Jafari
fonte
1
Observe que o uso de threads daemon pode causar outros problemas e provavelmente não são o que você deseja aqui: stackoverflow.com/questions/20596918/…
Doopy
12

Use o módulo atexit da biblioteca padrão do Python para registrar funções de "término" que são chamadas (no encadeamento principal) em qualquer encerramento razoavelmente "limpo" do encadeamento principal, incluindo uma exceção não capturada como KeyboardInterrupt. Essas funções de encerramento podem (embora inevitavelmente no thread principal!) Chamar qualquer stopfunção que você precisar; junto com a possibilidade de definir um thread como daemon, que lhe dá as ferramentas para projetar adequadamente a funcionalidade do sistema que você precisa.

Alex Martelli
fonte
Observe que essa abordagem funcionou sem exigir encadeamentos daemonizados nas versões do Python anteriores a 2.6.5, consulte a resposta para stackoverflow.com/questions/3713360/… . Este é um IMHO infeliz, já que os threads daemon durante o desligamento são um pouco confusos antes do python 3.4 ( bugs.python.org/issue19466 ). Se você parar e unir seus threads de daemon em seus manipuladores atexit, tudo ficará bem, ao custo (provavelmente insignificante) de serializar a desmontagem de thread.
NeilenMarais
Esteja ciente de que coisas estranhas podem acontecer por causa de atexit.register()chamadas posteriores aos módulos Python, fazendo com que seu procedimento de encerramento seja executado após o multiprocessingde um. Eu corro neste problema lidando com Queuee daemonthreads: “EOF error” na saída do programa usando multiprocessing Queue and Thread .
Delgan
Aparentemente, em versões modernas do Python, como 3.7.4+, os atexitmanipuladores não são chamados quando threads não daemon estão ativos e a thread principal sai. Consulte Script travado na saída ao usar atexit para encerrar threads .
martineau de
9

Se você gerar um Thread como este - myThread = Thread(target = function)- e então o faça myThread.start(); myThread.join(). Quando CTRL-C é iniciado, o thread principal não sai porque está aguardando aquela myThread.join()chamada de bloqueio . Para corrigir isso, basta colocar um tempo limite na chamada .join (). O tempo limite pode ser tão longo quanto você desejar. Se você quiser esperar indefinidamente, coloque um tempo limite realmente longo, como 99999. Também é uma boa prática fazer myThread.daemon = Truepara que todos os threads saiam quando o thread principal (não-daemon) for encerrado.

Milean
fonte
myThread.daemon = Trueé uma solução maravilhosa para este problema.
Brannon
5
@Brannon .daemon=Truenão é uma solução sólida. Verifique este tópico para obter uma explicação: stackoverflow.com/a/20598791/5562492
Odyssee
2

Os threads do daemon são eliminados de maneira desagradável, portanto, as instruções do finalizador não são executadas. Uma possível solução é verificar se o thread principal está ativo em vez de um loop infinito.

Por exemplo, para Python 3:

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

Consulte Verificar se o thread principal ainda está ativo em outro thread .

umi
fonte