42 votes

Comment empêcher une exception dans un thread d'arrière-plan de mettre fin à une application?

Je peux me connecter à AppDomain.CurrentDomain.UnhandledException pour consigner des exceptions provenant de threads d'arrière-plan, mais comment puis-je les empêcher de mettre fin à l'exécution?

9voto

Mitch Wheat Points 169614

De Joe Albahari excellent filetage de l'article:

L' .NET framework fournit un niveau inférieur événement global d'exception manipulation: Domaine d'application.UnhandledException. Cette l'événement se déclenche lorsqu'il y a un non gérée exception dans n'importe quel thread, et en tout type de la demande (avec ou sans interface utilisateur). Cependant, alors qu'il offre un bon dispositif de dernier recours pour l'exploitation forestière non interceptée exceptions, il ne fournit aucun moyen de prévention de la demande d'arrêter et de aucun moyen de réprimer l' .NET exception non gérée boîte de dialogue.

Dans les applications de production, explicite la gestion des exceptions est requis sur toutes les fil de méthodes d'entrée. On peut couper la de travail par l'utilisation d'un wrapper ou d'aide classe pour effectuer le travail, comme BackgroundWorker (discuté dans la Partie 3).

3voto

modosansreves Points 1678

En gardant la réponse courte, oui, vous pouvez empêcher le runtime de se terminer.

Voici une démonstration de la solution de contournement:

 class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}
 

En gros, vous n'avez pas laissé le moteur d'exécution afficher la boîte de dialogue "... le programme a cessé de fonctionner".

Au cas où vous auriez besoin de consigner l'exception et de quitter silencieusement , vous pouvez appeler Process.GetCurrentProcess().Kill();

1voto

aku Points 54867

Voici un excellent article de blog sur ce problème: Gestion des "exceptions non gérées" dans .NET 2.0

OMI, il serait juste de gérer manuellement les exceptions dans les threads d'arrière-plan et de les renvoyer via callback si nécessaire.

 delegate void ExceptionCallback(Exception ex);

void MyExceptionCallback(Exception ex)
{
   throw ex; // Handle/re-throw if necessary
}

void BackgroundThreadProc(Object obj)
{
   try 
   { 
     throw new Exception(); 
   }
   catch (Exception ex)
   { 
     this.BeginInvoke(new ExceptionCallback(MyExceptionCallback), ex); 
   }
}

private void Test()
{
   ThreadPool.QueueUserWorkItem(new WaitCallback(BackgroundThreadProc));
}
 

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