Browse DevX
Sign up for e-mail newsletters from DevX


Working with .NET Threads : Page 4

This article describes the dos and don'ts of the Thread class, and presents a wrapper class that simplifies starting a thread, correctly terminates a thread, and offers a more consistent class interface than that of the raw Thread class.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Interrupting a Waiting Thread
You can rudely awaken a sleeping or waiting thread by calling the Interrupt() method of the thread class:

public void Interrupt();

Background threads are a poor man's solution for application shutdown.
Calling Interrupt() unblocks a sleeping thread (or a waiting thread, such as a thread that called Join() on another thread), and throws an exception of type ThreadInterruptedException in the unblocked thread. If the code the thread executes does not catch that exception, then the thread is terminated by the runtime. If the thread is not sleeping (or waiting), and a call to Thread.Interrupt() is made, then the next time the thread tries to go to sleep (or wait), then .NET will immediately throw in its call stack the exception of type ThreadInterruptedException. Again, you should avoid relying on drastic solutions such as throwing exceptions to unblock another thread. Use .NET synchronization objects instead, to gain the benefits of structured and deterministic code flow. In addition, calling Interrupt() does not interrupt a thread that is executing unmanaged code via interop. Note that calling Interrupt() does not interrupt a thread that is in the middle of a call to SpinWait(), because that thread is actually not waiting at all (as far as the operation system is concerned).

Aborting a Thread
The Thread class provides an Abort() method, intended to forcefully terminate a .NET thread. Calling Abort() throws an exception of type ThreadAbortExceptionin the thread being aborted. ThreadAbortException is a special kind of exception: even if the thread method uses exception handling to catch exceptions, such as:

public void MyThreadMethod() { try { while(<some condition>) { <Do some work> } } catch { //Handle exceptions here } }

After the catch statement is executed, .NET re-throws the ThreadAbortException to terminate the thread. This is done so that non-structured attempts to ignore the abort by jumping to the beginning of the thread method will simply not work:

//Code that does not work when //ThreadAbortException is thrown. public void MyThreadMethod() { Resurrection: try { while(<some condition>) { <Do some work> } } catch { goto Resurrection; } }

If Abort() is called before the thread is started, .NET will never start the thread once Thread.Start() is called. If Thread.Abort() is called while the thread is blocked (either by calling Sleep(), or Join(), or if the thread is waiting on one of the .NET synchronization objects), .NET unblocks the thread and throws ThreadAbortException in it. However, you cannot call Abort() on a suspended thread. Doing so will result on the calling side with an exception of type ThreadStateException, with the error message "Thread is suspended; attempting to abort." In addition, .NET will terminate the suspended thread without letting it handle the exception.

The Thread class has an interesting counter-abort method—the static ResetAbort() method:

public static void ResetAbort();

Avoid controlling the application flow by setting Thread priorities.
Calling Thread.ResetAbort() in a catch statement prevents .NET from re-throwing ThreadAbortException at the end of the catch statement:

catch(ThreadAbortException exception) { Trace.WriteLine("Refusing to die"); Thread.ResetAbort(); //Do more processing or even go to somewhere }

Note that ResetAbort() demands the ControlThread security permission.

Terminating a thread by calling Abort() is not recommended for a number of reasons. The first is that it forces the thread to perform an ungraceful exit. Often the thread will need to release resources it holds and perform some sort of a cleanup before terminating. You can of course handle exceptions, and put the cleanup code in the finally method, but you typically want to handle the unexpected errors that way, and not use it as the standard way of terminating your thread. Never use exception to control the normal flow of your application—it is akin to non-structured programming using goto.

Second, nothing prevents the thread from abusing .NET and either performing as many operations as it likes in the catch statement or jumping to a label or calling ResetAbort(). If you want to terminate a thread, you should do so in a structured manner using the .NET synchronization objects. You should signal the Thread method to exit using a member variable or event.

Calling Thread.Abort() has another liability: if the thread makes an interop call (using COM Interop or P-Invoke), the interop call may take a while to complete. If Thread.Abort() is called during the interop call, .NET will not abort the thread, but lets it complete the interop call, only to abort it when it returns. This is yet another reason why Thread.Abort() is not guaranteed to succeed, or succeed immediately.

Thanks for your registration, follow us on our social networks to keep up-to-date