It seems that finally block doesn’t execute if it other than main thread execute code. Is it possible to force execute finally in that case?
Environment: VS 2010, .Net Framework 4.0.3
class Program
{
static void Main(string[] args)
{
var h = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(
obj => TestProc(h));
h.WaitOne();
}
private static void TestProc(EventWaitHandle h)
{
try
{
Trace.WriteLine("Try");
h.Set();
}
catch(Exception)
{
Trace.WriteLine("Catch");
}
finally
{
Thread.Sleep(2000);
Trace.WriteLine("Finally");
}
}
}
Update:
I found mentions and explanation about that case in MSDN:
ThreadAbortException Class
http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx
When a call is made to the Abort method to destroy a thread, the
common language runtime throws a ThreadAbortException.
ThreadAbortException is a special exception that can be caught, but it
will automatically be raised again at the end of the catch block. When
this exception is raised, the runtime executes all the finally blocks
before ending the thread. Because the thread can do an unbounded
computation in the finally blocks or call Thread.ResetAbort to cancel
the abort, there is no guarantee that the thread will ever end. If
you want to wait until the aborted thread has ended, you can call the
Thread.Join method. Join is a blocking call that does not return until
the thread actually stops executing.
Note:
When the common language runtime (CLR) stops background threads after
all foreground threads in a managed executable have ended, it does not
use Thread.Abort. Therefore, you cannot use ThreadAbortException to
detect when background threads are being terminated by the CLR.
Foreground and Background Threads http://msdn.microsoft.com/en-us/library/h339syd0.aspx
When the runtime stops a background thread because the process is shutting down, no exception is thrown in the thread. However, when threads are stopped because the AppDomain.Unload method unloads the application domain, a ThreadAbortException is thrown in both foreground and background threads.
So why at the end of application CLR doesn’t use AppDomain.Unload method for unloading the application domain before end (kill) of main process?
Because http://msdn.microsoft.com/en-us/library/system.appdomain.unload.aspx:
When a thread calls Unload, the target domain is marked for unloading.
The dedicated thread attempts to unload the domain, and all threads in
the domain are aborted. If a thread does not abort, for example
because it is executing unmanaged code, or because it is executing a
finally block, then after a period of time a
CannotUnloadAppDomainException is thrown in the thread that originally
called Unload. If the thread that could not be aborted eventually
ends, the target domain is not unloaded. Thus, in the .NET Framework
version 2.0 domain is not guaranteed to unload, because it might not
be possible to terminate executing threads.
Conclusion: In some cases I need to consider if will my code be executing in background or foreground thread? Is it possible that my code will not finished before application main thread ends all work?
Your code is running in a background thread. When you set the
AutoResetEvent, your single foreground thread terminates (as you reach the end of theMainmethod) and the process is torn down “immediately”.In fact, I think it likely that your
finallyblock starts executing, but as the first thing you do is sleep for two seconds, the process quits before it gets to yourWriteLinecall.If your
Mainmethod were still running, or any other foreground thread were keeping the process alive, you’d see yourfinallyblock complete as normal. This isn’t really a matter of “finally on other threads” – it’s a matter of “the process only stays alive while there are foreground threads”.