GOTCHA #55 Abort() takes time to clean upAs you saw in Gotcha #52, "ThreadAbortExceptiona hot potato," when you abort a THRead, the CLR throws a ThreadAbortException on it. The thread can do whatever cleanup it needs to by handling the exception. The CLR then executes all the finally blocks in the thread's call stack before actually terminating it. So there might be a delay between the time you call Abort() and the time the thread quits. This is illustrated in Example 7-7. Example 7-7. Delay during AbortC# (JoinAbort) using System; using System.Threading; namespace AbortAndJoin { class Test { private static void Worker() { Console.WriteLine("Worker started"); try { Thread.Sleep(5000); } finally { Console.WriteLine("Worker enters finally {0}", DateTime.Now.ToLongTimeString()); Thread.Sleep(10000); // Simulates some cleanup activity Console.WriteLine("Cleanup done in Worker {0}", DateTime.Now.ToLongTimeString()); } } [STAThread] static void Main(string[] args) { Thread workerThread = new Thread(new ThreadStart(Worker)); workerThread.IsBackground = true; workerThread.Start(); Thread.Sleep(1000); Console.WriteLine("Aborting thread {0}", DateTime.Now.ToLongTimeString()); workerThread.Abort(); workerThread.Join(); Console.WriteLine("Thread has aborted {0}", DateTime.Now.ToLongTimeString()); } } } VB.NET (JoinAbort) Imports System.Threading Module Test Private Sub Worker() Console.WriteLine("Worker started") Try Thread.Sleep(5000) Finally Console.WriteLine("Worker enters finally {0}", _ DateTime.Now.ToLongTimeString()) Thread.Sleep(10000) ' Simulates some cleanup activity Console.WriteLine("Cleanup done in Worker {0}", _ DateTime.Now.ToLongTimeString()) End Try End Sub Public Sub Main() Dim workerThread As New Thread(AddressOf Worker) workerThread.IsBackground = True workerThread.Start() Thread.Sleep(1000) Console.WriteLine("Aborting thread {0}", _ DateTime.Now.ToLongTimeString()) workerThread.Abort() workerThread.Join() Console.WriteLine("Thread has aborted {0}", _ DateTime.Now.ToLongTimeString()) End Sub End Module In this example, the Worker() method's finally block introduces a delay to simulate some activity. Main() first starts a thread to run the Worker() method. After a delay, it invokes Abort() on that thread. Then it calls Join() to wait for cleanup and completion. The output is shown in Figure 7-8. Figure 7-8. Output from Example 7-7If your application requires you to Abort() a thread and perform some operation after that thread has quit, you should call Join() on the thread after calling Abort(). This waits for the thread to clean up properly and exit gracefully before you continue processing.
IN A NUTSHELLAsk yourself if you should call Join() after a call to Abort(). That is, ask if you need to wait for the thread to actually quit. SEE ALSOGotcha #52, "ThreadAbortExceptiona hot potato" and Gotcha #54, "ResetAbort() may lead to surprises." |