C # Thread Termination e Thread.Abort ()

85

No MSDN, a descrição do método Thread.Abort () diz: "Chamar esse método geralmente encerra o thread."

Por que não SEMPRE?

Em quais casos ele não encerra o tópico?

Existe alguma outra possibilidade de encerrar tópicos?

user101375
fonte

Respostas:

60

Thread.Abort()injeta um ThreadAbortExceptionno segmento. O thread pode cancelar o pedido chamando Thread.ResetAbort(). Além disso, há certas partes do código, como o finallybloco que será executado antes que a exceção seja tratada. Se, por algum motivo, o encadeamento estiver preso em tal bloco, a exceção nunca será gerada no encadeamento.

Como o chamador tem muito pouco controle sobre o estado do thread ao chamar Abort(), geralmente não é aconselhável fazer isso. Em vez disso, passe uma mensagem para o thread solicitando o encerramento.

Brian Rasmussen
fonte
Que tipo de mensagem? Você quer dizer uma invocação de método?
user101375
4
Isso depende de como você passa dados entre seus threads. Por exemplo, se seu thread é um thread de trabalho com uma fila de tarefas, você pode enfileirar uma mensagem PleaseTerminate e deixar o thread lidar com isso normalmente.
Brian Rasmussen
Meu tópico tem um grande problema que precisa ser resolvido, onde não há fila de tarefas.
user101375
Como eu disse, depende de como seu código de thread foi projetado. Talvez você possa sinalizar por meio de uma variável membro então. É difícil ser mais específico sem o código real disponível.
Brian Rasmussen
54

Em quais casos ele não encerra o tópico?

Esta pergunta é uma duplicata.

O que há de errado em usar Thread.Abort ()

Existe alguma outra possibilidade de encerrar os tópicos?

Sim. O seu problema é que você nunca deve iniciar um tópico que você não pode dizer educadamente para parar, e ele termina em tempo hábil. Se você está em uma situação em que precisa iniciar um tópico que pode ser (1) difícil de interromper, (2) com erros ou pior de tudo (3) hostil para o usuário, a coisa certa a fazer é fazer um novo processo, inicie o thread no novo processo e, em seguida, encerre o processo quando quiser que o thread seja desativado. A única coisa que pode garantir o encerramento seguro de um thread não cooperativo é o sistema operacional interrompendo todo o seu processo.

Veja minha resposta excessivamente longa a esta pergunta para mais detalhes:

Usando a instrução de bloqueio em um loop em C #

A parte relevante é a parte no final em que discuto quais são as considerações sobre quanto tempo você deve esperar até que um thread se mate antes de abortá-lo.

Eric Lippert
fonte
Eric, como devo dizer educadamente a um encadeamento para parar se esse encadeamento está aguardando um objeto de sincronização, por exemplo, EventWaitHandle.WaitOne () ;?
Corvin
5
@Corvin: o contrato entre dois encadeamentos que descreve como um encadeamento deve se comunicar com outro é responsabilidade dos autores do código executado nesses encadeamentos. Se você tem requisitos de que (1) um encadeamento X deve esperar em um objeto potencialmente para sempre e (2) esse encadeamento Y deve ser capaz de encerrar o encadeamento X de forma limpa em um período de tempo finito, então acho que você tem requisitos contraditórios; decida qual ganha. Se for o primeiro, o segmento Y terá que esperar. Se for o último, o thread X não deve ficar esperando para sempre, deve esperar um pequeno período de tempo.
Eric Lippert
Obrigado por responder. Considere a seguinte arquitetura: Eu tenho um aplicativo que precisa se minimizar quando um determinado evento de todo o sistema acontece. Eu tenho um thread nesse aplicativo que aguarda um evento nomeado global e faz seu trabalho quando esse evento é definido. Por outro lado, meu aplicativo pode ter que ser encerrado antes que o evento aconteça, tendo que fechar aquele thread em espera. Qual é a maneira de um samurai codificar tal coisa?
Corvin de
@Corvin: Você pode ter um loop que espera (com um curto tempo limite) pelo evento e, em seguida, verifica se deve parar de tentar esperar (para que possa sair normalmente). Dessa forma, você pode sinalizar ao seu encadeamento que ele deve parar, e você só deve esperar o tempo limite para que ele pare.
Kevin Kibler
2
@Corvin, se você transformar esse thread em espera em um thread de segundo plano, não deverá ter que fechá-lo antes que o aplicativo feche.
Don Kirkby
17

Por que não SEMPRE? Em quais casos ele não termina o segmento?

Para começar, um thread pode capturar a ThreadAbortExceptione cancelar seu próprio encerramento. Ou pode realizar um cálculo que leva uma eternidade enquanto você tenta abortá-lo. Por causa disso, o tempo de execução não pode garantir que o encadeamento sempre será encerrado depois que você solicitar.

ThreadAbortException tem mais:

Quando uma chamada é feita para o método Abort para destruir um thread, o common language runtime lança um ThreadAbortException. ThreadAbortException é uma exceção especial que pode ser detectada, mas será automaticamente gerada novamente no final do bloco catch. Quando essa exceção é levantada, o tempo de execução executa todos os blocos finally antes de encerrar o thread. Uma vez que o encadeamento pode fazer um cálculo ilimitado nos blocos finally, ou chamar Thread.ResetAbort()para cancelar o aborto, não há garantia de que o encadeamento acabará.

Você não precisa de Abort()um thread manualmente. O CLR fará todo o trabalho sujo para você se você simplesmente deixar o método no thread retornar; isso encerrará o tópico normalmente.

John Feminella
fonte
Eu preciso Abort (), por causa de um loop de mensagem iniciado nesse segmento (Dispatcher.Run ();). Se eu entendi correto, preciso invocar um método de chamada de retorno no thread para concluí-lo?
user101375
7

FileStream.Read()para um pipe nomeado que atualmente não está recebendo nada (leia os blocos de chamadas enquanto espera pelos dados de entrada) não responderá Thread.Abort(). Ele permanece dentro da Read()chamada.

Jovain
fonte
6

E se um thread estiver travando e for interrompido / eliminado? Os recursos permanecem presos

Funciona bem quando um thread chama o aborto, mas não por outro thread. Abortar, encerra à força o encadeamento afetado, mesmo que não tenha concluído sua tarefa e não ofereça oportunidade para a limpeza de recursos

referência MSDN


consulte: Melhores práticas de segmentação gerenciada

Asad
fonte
5

Não consigo abortar um thread que está preso em um loop:

//immortal
Thread th1 = new Thread(() => { while (true) {}});

No entanto, posso abortar o thread se dormir durante o loop:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});
Colin
fonte
1
isso não parece ser verdade, executei um programa de teste: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Exception e) { Console.WriteLine ("aborting @ {0}", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L
3

Porque você pode capturar o ThreadAbortExceptione chamar Thread.ResetAbortdentro do manipulador.

Erikkallen
fonte
0

OT: Para uma abordagem abrangente, independente de linguagem, questionavelmente útil e muito engraçada sobre simultaneidade, consulte Verity Stob !

Pontus Gagge
fonte
-1

Tive casos em que o thread estava muito ocupado para ouvir a chamada Abort (), o que geralmente resulta em uma ThreadAbortingException sendo lançada em meu código.

Andy Shellam
fonte