Recipe 15.3 Preventing Silent Thread Termination
Problem
An exception thrown in a spawned
worker thread will cause this thread to be silently terminated if the
exception is unhandled. You need to make sure all exceptions are
handled in all threads. If an exception happens in this new thread,
you want to handle it and be notified of its occurrence.
Solution
You
must add exception handling to the method that you pass to the
ThreadStart delegate with a
try/catch, try/finally, or
try/catch/finally block. The code to do this is
shown here in bold:
using System;
using System.Threading;
public class MainThread
{
public void CreateNewThread( )
{
// Spawn new thread to do concurrent work
Thread newWorkerThread = new Thread(new ThreadStart(Worker.DoWork));
newWorkerThread.Start( );
}
}
public class Worker
{
// Method called by ThreadStart delegate to do concurrent work
public static void DoWork ( )
{
try
{
// Do thread work here
}
catch
{
// Handle thread exception here
// Do not re-throw exception
}
finally
{
// Do thread cleanup here
}
}
}
Discussion
If an unhandled exception occurs in the main thread of an
application, the main thread terminates, along with your entire
application. An unhandled exception in a spawned worker thread,
however, will terminate only that thread. This will happen without
any visible warnings, and your application will continue to run as if
nothing happened.
Simply wrapping an exception handler around the
Start method of the Thread
class will not catch the exception on the newly created thread. The
Start method is called within the context of the
current thread, not the newly created thread. It also returns
immediately once the thread is launched, so it isn't
going to wait around for the thread to finish. Therefore, the
exception thrown on the new thread will not be caught since it is not
visible to any other threads.
If the exception is rethrown from the catch block,
the finally block of this structured exception
handler will still execute. However, after the
finally block is finished, the rethrown exception
is, at that point, rethrown. The rethrown exception cannot be handled
and the thread terminates. If there is any code after the
finally block, it will not be executed, since an
unhandled exception occurred.
|
Never rethrow an exception at the highest point in the exception
handling hierarchy within a thread. Since no exception handlers can
catch this rethrown exception, it will be considered unhandled and
the thread will terminate after all finally blocks
have been executed.
|
|
What if you were using the ThreadPool and
QueueUserWorkItem? This method would still help
you because you added the handling code that will execute inside the
thread. Just make sure you have the finally block
set up so that you can notify yourself of exceptions in other threads
as shown earlier.
In order to provide a last chance exception handler for your WinForms
application, you would need to hook up for two separate events. The
first event is the
System.AppDomain.CurrentDomain.UnhandledException
event, which will catch all unhandled exceptions in the current
AppDomain on worker threads; it will not catch exceptions that occur
on the main UI thread of a WinForms application. In order to catch
those, you also need to hook up to the
System.Windows.Forms.Application.ThreadException,
which will catch unhandled exceptions in the main UI thread.
See Also
See the "Thread Class" and
"Exception Class" topics in the
MSDN documentation.
|