Partager via


Assistant Débogage managé asynchronousThreadAbort

Remarque

Cet article est spécifique au .NET Framework. Elle ne s’applique pas aux implémentations plus récentes de .NET, notamment .NET 6 et versions ultérieures.

L’Assistant Débogage managé (MDA) asynchronousThreadAbort est activé quand un thread tente d’introduire un abandon asynchrone dans un autre thread. Les abandons de threads synchrones n’activent pas l’Assistant Débogage managé asynchronousThreadAbort.

Symptômes

Une application se bloque avec une exception ThreadAbortException non gérée quand le thread d’application principal est abandonné. Si l’application continuait à s’exécuter, les conséquences pourraient être pires qu’un blocage, entraînant éventuellement un endommagement supplémentaire des données.

Des opérations censées être atomiques ont probablement été interrompues après l’achèvement partiel, laissant les données d’application dans un état imprévisible. Une exception ThreadAbortException peut être générée à partir de points apparemment aléatoires dans l’exécution du code, souvent à des endroits à partir desquels une exception n’est pas censée se produire. Le code n’est peut-être pas capable de gérer cette exception, entraînant un état endommagé.

Les symptômes peuvent varier considérablement en raison du caractère aléatoire du problème.

Cause

Le code dans un thread a appelé la méthode Thread.Abort sur un thread cible pour introduire un abandon de thread asynchrone. L’abandon de thread est asynchrone, car le code qui effectue l’appel à Abort s’exécute sur un thread différent de la cible de l’opération d’abandon. Les abandons de threads synchrones ne doivent pas provoquer de problème, car le thread exécutant Abort doit l’avoir fait uniquement à un point de contrôle sécurisé où l’état de l’application est cohérent.

Les abandons de threads asynchrones présentent un problème, car ils sont traités à des points inattendus dans l’exécution du thread cible. Pour éviter cela, le code écrit pour s’exécuter sur un thread susceptible d’être abandonné de cette manière aurait besoin de gérer une exception ThreadAbortException presque à chaque ligne de code, en prenant soin de remettre les données d’application dans un état cohérent. Il n’est pas réaliste de s’attendre à ce que le code soit écrit avec ce problème à l’esprit, ni d’écrire du code qui protège contre tous les cas possibles.

Les appels dans le code non managé et les blocs finally ne seront pas abandonnés de façon asynchrone, mais dès la sortie de l’une de ces catégories.

La cause peut être difficile à déterminer en raison du caractère aléatoire du problème.

Résolution

Évitez les conceptions du code qui exigent l’utilisation d’abandons de threads asynchrones. Il existe plusieurs approches plus appropriées pour l’interruption d’un thread cible qui ne nécessitent pas d’appel à Abort. La plus sûre consiste à introduire un mécanisme, par exemple une propriété commune, qui envoie un signal au thread cible pour demander une interruption. Le thread cible vérifie ce signal à certains points de contrôle sécurisés. S’il remarque qu’une interruption a été demandée, il peut s’arrêter correctement.

Effet sur le runtime

Cet Assistant Débogage managé n'a aucun effet sur le CLR. Il signale uniquement des données sur les abandons de threads asynchrones.

Sortie

L’Assistant Débogage managé signale l’ID du thread qui exécute l’abandon et l’ID du thread qui est la cible de l’abandon. Ces ID ne sont jamais les mêmes, car ce scénario se limite aux abandons asynchrones.

Configuration

<mdaConfig>
  <assistants>
    <asynchronousThreadAbort />
  </assistants>
</mdaConfig>

Exemple

L’activation de l’Assistant Débogage managé asynchronousThreadAbort nécessite uniquement un appel à Abort sur un thread en cours d’exécution distinct. Tenez compte des conséquences si le contenu de la fonction de démarrage du thread était un ensemble d’opérations plus complexes susceptibles d’être interrompues à un point arbitraire par l’abandon.

using System.Threading;
void FireMda()
{
    Thread t = new Thread(delegate() { Thread.Sleep(1000); });
    t.Start();
    // The following line activates the MDA.
    t.Abort();
    t.Join();
}

Voir aussi