Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When will AppDomain.ProcessExit not get called?

Enabling line //1 below will make the program crash without "proc exit" being printed, but in case of line //2, "proc exit" will be printed. "unhandled" btw gets printed in both cases.

Why the difference, and what are the rules in general? Obviously killing an app using e.g. the task manager will prevent "proc exit" from being printed, but other than that, what are the cases it doesn't get printed?

static void Main(string[] args)
{
    Thread.GetDomain().UnhandledException +=
        (sender, eventArgs) => Console.WriteLine("unhandled");
    AppDomain.CurrentDomain.ProcessExit +=
        (sender, eventArgs) => Console.WriteLine("proc exit");
    //1 new Thread(_ => { throw new Exception(); }).Start();
    //2 ThreadPool.QueueUserWorkItem(_ => { throw new Exception(); });
    Thread.Sleep(1000);
    return;
like image 389
Evgeniy Berezovsky Avatar asked Dec 19 '13 06:12

Evgeniy Berezovsky


Video Answer


1 Answers

Please take a look at this blog post: AppDomain.ProcessExit is not guaranteed to be called. Quoted from the post:

The AppDomain.ProcessExit is not guaranteed to be called. It's pretty resilient and will deal with common things you may cause from low-trust IL (exceptions, out-of-memory, etc), but there are some things (like rude process shutdown), that an inprocess event can never be resilient against.

(...)

The callback is invoked from within the process. If the process rudely exits, the callback would not be invoked. Common sources for rudely exiting include:

  1. Killed externally via TaskManager or kernel32!TerminateProcess.
  2. Stackoverflow handler consumes past the guard page.

The ProcessExit event is like telling somebody "please telephone me that your about to die". If death comes quickly enough, they may not get the message out.

In fact, I have tried out your code and it does never print "proc exit" when uncommenting line 1 or even line 2! (I have tried compiling against all .NET versions, in Visual Studio 2013). Of course it does print it when no exceptions are thrown and the process exits normally. (EDIT: I see the "proc exit" message if I compile the code in Release mode, but not when I compile in Debug mode)

As a side note, here is a suggested refactor for your code (not fully tested and probably incomplete, but you get the idea):

static void Main(string[] args)
{
    Thread.GetDomain().UnhandledException +=
        (sender, eventArgs) => Exiting((Exception)eventArgs.ExceptionObject);
    AppDomain.CurrentDomain.ProcessExit +=
        (sender, eventArgs) => Exiting(null);
    //1 new Thread(_ => { throw new Exception(); }).Start();
    //2 ThreadPool.QueueUserWorkItem(_ => { throw new Exception(); });
    Thread.Sleep(1000);
    return;
}

static void Exiting(Exception exception)
{
    //Put common cleanup code here (or at the end of the method)

    if(exception == null)
    {
        Console.WriteLine("normal proc exit");
    }
    else
    {
        Console.WriteLine("unhandled exception: " + exception.GetType().Name);
    }
}
like image 97
Konamiman Avatar answered Oct 20 '22 01:10

Konamiman