Terminaison de thread C # et Thread.Abort ()

85

Dans MSDN, la description de la méthode Thread.Abort () indique: «L'appel de cette méthode met généralement fin au thread».

Pourquoi pas TOUJOURS?

Dans quels cas cela ne met pas fin au thread?

Existe-t-il une autre possibilité de terminer les threads?

utilisateur101375
la source

Réponses:

60

Thread.Abort()injecte un ThreadAbortExceptionsur le fil. Le thread peut annuler la demande en appelant Thread.ResetAbort(). En outre, certaines parties de code, telles qu'un finallybloc, s'exécutent avant que l'exception ne soit gérée. Si pour une raison quelconque le thread est bloqué dans un tel bloc, l'exception ne sera jamais levée sur le thread.

Comme l'appelant a très peu de contrôle sur l'état du thread lors de l'appel Abort(), il n'est généralement pas conseillé de le faire. Passez plutôt un message au thread demandant l'arrêt.

Brian Rasmussen
la source
Quel genre de message? Voulez-vous dire une invocation de méthode?
user101375
4
Cela dépend de la manière dont vous transmettez les données entre vos threads. Par exemple, si votre thread est un thread de travail avec une file d'attente de tâches, vous pouvez mettre en file d'attente un message PleaseTerminate et laisser le thread le gérer correctement.
Brian Rasmussen
Mon thread a un gros problème qui doit être résolu, il n'y a pas de file d'attente de tâches.
user101375
Comme je l'ai dit, cela dépend de la façon dont votre code de thread est conçu. Vous pourriez peut-être alors signaler via une variable membre. Il est difficile d'être plus précis sans le code réel disponible.
Brian Rasmussen
54

Dans quels cas cela ne met pas fin au thread?

Cette question est un double.

Quel est le problème avec l'utilisation de Thread.Abort ()

Existe-t-il une autre possibilité de terminer les threads?

Oui. Votre problème est que vous ne devriez jamais démarrer un thread auquel vous ne pouvez pas dire poliment d'arrêter, et il s'arrête en temps opportun. Si vous êtes dans une situation où vous devez démarrer un thread qui pourrait être (1) difficile à arrêter, (2) bogué, ou pire de tous (3) hostile à l'utilisateur, alors la bonne chose à faire est de faire un nouveau processus, démarrez le thread dans le nouveau processus, puis arrêtez le processus lorsque vous souhaitez que le thread s'arrête. La seule chose qui peut garantir l'arrêt en toute sécurité d'un thread non coopératif est que le système d'exploitation supprime tout son processus.

Voir ma réponse excessivement longue à cette question pour plus de détails:

Utilisation de l'instruction de verrouillage dans une boucle en C #

Le bit pertinent est le bit à la fin où je discute de ce que sont les considérations concernant combien de temps vous devez attendre qu'un thread se tue avant de l'abandonner.

Eric Lippert
la source
Eric, comment dois-je poliment dire à un thread de s'arrêter si ce thread attend un objet de synchronisation, par exemple EventWaitHandle.WaitOne () ;?
Corvin
5
@Corvin: le contrat entre deux threads qui décrit comment un thread doit communiquer avec un autre appartient aux auteurs du code qui s'exécute sur ces threads. Si vous avez des exigences selon lesquelles (1) un thread X doit attendre un objet potentiellement pour toujours, et (2) ce thread Y doit être capable d'arrêter proprement le thread X dans un laps de temps limité, alors je pense que vous avez des exigences contradictoires; décider lequel gagne. Si c'est le premier, le fil Y va devoir attendre. Si ce dernier, le thread X ne devrait pas attendre indéfiniment, il devrait attendre un peu de temps.
Eric Lippert
Merci de répondre. Considérez l'architecture suivante: J'ai une application qui doit se minimiser lorsqu'un certain événement à l'échelle du système se produit. J'ai un fil dans cette application qui attend un événement nommé global et fait son travail lorsque cet événement est défini. De l'autre côté, mon application devra peut-être se fermer avant que l'événement ne se produise, en fermant ce thread en attente. Quelle est la manière samouraï de coder une telle chose?
Corvin
@Corvin: Vous pourriez avoir une boucle qui attend (avec un court délai) pour l'événement, puis vérifie si elle doit arrêter d'essayer d'attendre (pour qu'elle puisse se terminer normalement). De cette façon, vous pouvez signaler à votre thread qu'il doit s'arrêter et vous ne devriez avoir à attendre que le temps imparti pour qu'il s'arrête.
Kevin Kibler
2
@Corvin, si vous faites de ce thread en attente un thread d'arrière-plan, vous ne devriez pas avoir à le fermer avant que l'application se ferme.
Don Kirkby
17

Pourquoi pas TOUJOURS? Dans quels cas il ne termine pas le fil?

Pour commencer, un thread peut intercepter un ThreadAbortExceptionet annuler sa propre terminaison. Ou il pourrait effectuer un calcul qui prend une éternité pendant que vous essayez de l'abandonner. Pour cette raison, le runtime ne peut pas garantir que le thread se terminera toujours une fois que vous le lui aurez demandé.

ThreadAbortException a plus:

Lorsqu'un appel est effectué à la méthode Abort pour détruire un thread, le Common Language Runtime lève une ThreadAbortException. ThreadAbortException est une exception spéciale qui peut être interceptée, mais elle sera automatiquement déclenchée à nouveau à la fin du bloc catch. Lorsque cette exception est déclenchée, le runtime exécute tous les blocs finally avant de terminer le thread. Puisque le thread peut faire un calcul illimité dans les blocs finally, ou appeler Thread.ResetAbort()pour annuler l'abandon, il n'y a aucune garantie que le thread se terminera un jour.

Vous n'avez pas besoin d' Abort()un thread manuellement. Le CLR fera tout le sale boulot pour vous si vous laissez simplement la méthode dans le thread retourner; cela mettra fin au fil normalement.

John Feminella
la source
J'ai besoin de l'abandonner (), à cause d'une boucle de message démarrée sur ce thread (Dispatcher.Run ();). Si je comprends bien, je dois appeler une méthode appelant return dans le thread pour le terminer?
user101375
7

FileStream.Read()vers un tube nommé qui ne reçoit actuellement rien (lire les blocs d'appels en attendant les données entrantes) ne répondra pas Thread.Abort(). Il reste à l'intérieur de l' Read()appel.

jovain
la source
6

Que faire si un thread détient un verrou et est abandonné / tué? Les ressources restent bloquées

Cela fonctionne bien lorsqu'un thread appelle s'abandonner mais pas par un autre thread. Abort, met fin de force au thread affecté même s'il n'a pas terminé sa tâche et ne donne aucune possibilité de nettoyage des ressources

référence MSDN


voir: Meilleures pratiques de gestion de threads

Asad
la source
5

Je n'arrive pas à interrompre un thread qui est coincé dans une boucle:

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

Je peux cependant abandonner le thread s'il dort pendant la boucle:

//mortal
Thread th2 = new Thread(() => { while (true) { Thread.Sleep(1000); }});
Colin
la source
1
cela ne semble pas être vrai, j'ai exécuté un programme de test: `{var th = new Thread (() => {int i = 0; try {while (true) {i ++;}} catch (Exception e) { Console.WriteLine ("abandonner @ {0}", i);}}); th.Start (); Thread.Sleep (1000); th.Abort (); th.Join (); }
Weipeng L
3

Parce que vous pouvez attraper ThreadAbortExceptionet appeler Thread.ResetAbortà l'intérieur du gestionnaire.

Erikkallen
la source
0

OT: Pour une interprétation complète, indépendante de la langue, discutablement utile et vraiment amusante sur la concurrence, voir Verity Stob !

Pontus Gagge
la source
-1

J'ai eu des cas où le thread était trop occupé pour entendre l'appel Abort (), ce qui se traduit généralement par une ThreadAbortingException renvoyée à mon code.

Andy Shellam
la source