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:
- Killed externally via TaskManager or kernel32!TerminateProcess.
- 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);
}
}