Yeah, one of the favorite
questions of any interviewer when it comes to multithreading.
Are you thinking of
Thread.Abort()? Let us see why we shouldn't we consider Abort() on a thread. If
below information looks like content of MSDN, bear with me because most of the concepts
in this article are from MSDN pages only.
è When thread abort
method is called, ThreadAbortException is raised in the method that is being executed. Even if the exception is handled in the
thread method, it is re-thrown at the end of catch block. Yes,
ThreadAbortException is a special kind of exception which is thrown even when
it is assumed to be "handled".
è Unexecuted finally blocks are executed before the thread is
aborted. The thread is not guaranteed to abort immediately, or at all.
This situation can occur if a thread does an unbounded amount of computation in
the finally blocks that are called as part of the
abort procedure, thereby indefinitely delaying the abort. To wait until a
thread has aborted, you can call the Join method
on the thread after calling the Abort method, but there is no guarantee the
wait will end.
è
If Abort is
called on a thread that has been suspended, a ThreadStateException is thrown in the thread that called Abort, and AbortRequested is added to the ThreadStateproperty of the thread being
aborted. A ThreadAbortException is not thrown in the suspended thread
until Resume is
called.
è
If Abort is
called on a managed thread while it is executing unmanaged code, a ThreadAbortException is not thrown until the thread returns
to managed code.
è
If two calls to Abort come
at the same time, it is possible for one call to set the state information and
the other call to execute the Abort. However, an application cannot detect this
situation.
Now that we saw why
terminating a thread by calling Thread.Abort is not a good idea. Let us discuss
few approaches of terminating a thread in safer way.
Method 1 – using volatile variable:
Variables that are
marked as “volatile” can be accessed across multiple threads in thread-safe
manner. We can use this property of volatile variable to control the execution
of thread method. Yes, we can terminate the thread based on the value of this
volatile variable, the caller can simply set this variable from its code.
Little about volatile
keyword:
“The volatile keyword indicates that a
field might be modified by multiple threads that are executing at the same
time. Fields that are declared volatile are
not subject to compiler optimizations that assume access by a single thread.
This ensures that the most up-to-date value is present in the field at all
times.
The volatile modifier
is usually used for a field that is accessed by multiple threads without using
the lock statement
to serialize access.”
A
simple but not so accurate example (copy pasted from StackOverflow as-it-is):
volatile bool shutdown = false;
void RunThread()
{
while (!shutdown)
{
...
}
}
void StopThread()
{
shutdown = true;
}
This
allows your thread to cleanly finish what it was doing, leaving your app in a
known good state.
Method 2 using
Thread.Interrupt(), volatile and exception handling for cleaned up termination:
ThreadInterruptedException
is an exception which can be handled in the thread method. Thread.Interrupt can
be called only on a thread that is in WaitSleepJoin state. Calling Interrupt when a thread is in the WaitSleepJoin state will cause a ThreadInterruptedException to
be thrown in the target thread. If the thread is not in the WaitSleepJoin state, the exception is not thrown
until the thread enters that state. If the thread never blocks, it could
complete without ever being interrupted.
Approach
is to handle this exception in the target thread method and exit gracefully.
Combining this with a volatile variable like in method 1 will provide much
safer way to terminate the thread. It also assures that thread will be “aborted”,
sorry let us say terminated even when thread may block in a “sleep” or “wait”
state.
Again
an example from StackOverflow(as-it-is copied):
try
{
while (keepGoing)
{
/* Do work. */
}
}
catch (ThreadInterruptedException exception)
{
/* Clean up. */
}
I have compiled this
article from the answers I read on StackOverflow and MSDN articles. If you find
useful please thank me by liking this post.