50 votes

ThreadAbortException

Disons que nous avons du code comme celui-ci en cours d'exécution dans le thread séparé:

 private static void ThreadFunc() {
    ulong counter = 0;

    while (true) {

        try {
            Console.WriteLine( "{0}", counter++ );
        }
        catch (ThreadAbortException) {
            Console.WriteLine( "Abort!" );
        }

    }
}
 

Lorsque Thread.Abort() est appelé, est-il possible que l'exception soit levée en dehors du bloc catch?

78voto

Josh Points 38617

En fait oui, un ThreadAbortException est spécial. Même si vous la prenez en main, elle sera automatiquement rejetée par le CLR, à la fin du try/catch/finally. (Comme indiqué dans les commentaires, il peut être supprimé avec ResetAbort mais à ce stade, le code sent le poisson pourri.)

Ne pas mentionner, même si il n'est pas évident du code exécutable à l'extérieur de votre try/catch/finally, chaque itération de la boucle des vents hors de la portée pour une petite durée, donc l'abandon pourrait se produire à l'extérieur de votre bloc try.

Sauf si vous êtes en train de faire quelque chose dans le bloc catch, je voudrais juste faire un try/finally et ne vous inquiétez pas à propos de ThreadAbortException. Il y a beaucoup des meilleurs moyens d'avorter d'un thread sans l'aide d' Thread.Abort qui non seulement chaotique interrompt votre code à un imprévisible point, c'est pas garanti pour fonctionner, parce que si le thread est actuellement en appelant à certains de code non managé, le fil ne sera pas abandonner jusqu'à ce que le contrôle retourne au code managé.

C'est beaucoup mieux d'utiliser un certain type de primitives de synchronisation comme un ManualResetEvent d'agir comme un drapeau en parler à votre fil quand à la sortie. Vous pourriez même utiliser un champ booléen à cet effet qui est ce que le BackgroundWorker n'.

21voto

Jon Skeet Points 692016

Oui. Je soupçonne que vous demandez parce que le thread des interruptions se produisent uniquement lorsqu'un thread, autrement, pourraient bloquer (ou si c'est déjà bloqué) - par exemple pour les IO.

Il n'y a pas de garantie pour l'annuler. Il peut arriver à tout moment, fondamentalement, même si il y a retard à l'abandon des régions comme l' exécution limitées régions et catch/finally blocs, où la demande d'annulation est juste de rappeler, et le fil interrompu lorsqu'il quitte la région.

Synchrone abandons de thread (c'est à dire l'abandon de votre propre thread) est raisonnablement sûr, mais abandons asynchrones (abandon d'une différents thread) sont presque toujours une mauvaise idée. Lire "la Programmation Simultanée sur Windows" par Joe Duffy pour de plus amples informations.

EDIT: Comme le fait remarquer Eric ci-dessous, l'abandon d'un autre thread n'est pas garanti d'avoir un quelconque effet. Juste pour citer le commentaire:

J'aurais dit que le thread est interrompu si le sort de la région, soulignant qu' Thread.Abort est totalement fiable. Un thread qui être annulée parce qu'elle est bloqué dans une boucle infinie ne va pas abandonner si la boucle est dans une telle région. C'est encore une autre raison d' Thread.Abort est une mauvaise idée; si vous ne pouvez pas compter sur l'effet recherché en fait ce qui se passe alors, pourquoi voulez-vous appeler la méthode?

7voto

Ilya Builuk Points 919

En fait, ThreadAbortException est spécial dans le cas où il est lancé par le CLR ou Thread.Abandon de la méthode. Comparer de sortie:

  • Légèrement modifiée exemple (ajouté Console.WriteLine) de Joe Duffy "la Programmation Simultanée sur Windows". Il lève l'exception par Thread.CurrentThread.Abandonner:
    
    try
    {
        try
        {
            Thread.CurrentThread.Abort();
        }
        catch (ThreadAbortException)
        {
            Console.WriteLine("First");
            //Try to swallow it.
        } //CLR automatically reraises the exception here .
    }
    catch (ThreadAbortException)
    {
        Console.WriteLine("Second");
        Thread.ResetAbort();
        //Try to swallow it again .
    } //The in - flight abort was reset , so it is not reraised again .
    
    
    
    Sortie:
    Première
    Deuxième
    
  • Modifier exemple précédent pour l'utilisation différente de l'approche de ThreadAbortException création de l'instance:
    
    try
    {
        try
        {
            // get non-public constructor
            var cstor = typeof(ThreadAbortException)
                .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
            // create ThreadAbortException instance
            ThreadAbortException ex = cstor.Invoke(null) as ThreadAbortException;
    
            // throw..
            throw ex;
        }
        catch (ThreadAbortException)
        {
            Console.WriteLine("First");
        } 
    }
    catch (ThreadAbortException)
    {
        Console.WriteLine("Second");
        Thread.ResetAbort();
    } 
    
    Sortie:
    Première
    

Il semble que du Thread méthodes d'appeler du code natif en interne, qui permet a soulevé une exception spécifique.

4voto

Andrew Hare Points 159332

Je ne suis pas 100% de ce que vous demandez, mais je tenais à préciser que vous ne serez jamais capable d'avaler un ThreadAbortException:

Lorsqu'un appel est effectué à l'Abandon méthode pour détruire un thread, la commune language runtime jette un ThreadAbortException. ThreadAbortException est un spécial exception qui peut être pris, mais il sera automatiquement soulevé de nouveau à la fin du bloc catch.

Demandez-vous si il est possible de prendre un ThreadAbortException qui se jette dans un autre thread ici avec un try/catch? Si c'est votre question, alors non, vous ne pouvez pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X