Please see my comments to the question. There must be a call to
Thread.Abort
somewhere. And your dedicate thread and the wait for the termination of the child process should have a reason, but this is not shown in your code.
Exceptions are not errors. (Important point many developers miss.) The exception
System.Threading.ThreadAbortException
is the very important exception used to process asynchronous
Thread.Abort
. It is used in the thread being aborted and allows this thread to exit correctly after abort, performing some post-mortal will of the thread, so it can finalize important object and perform other actions making abortion of the thread safe and correct. In many cases, this aspect of programming is not trivial.
Before explaining how it works, let me give you
a word of warning. The method
Thread.Abort
is a very powerful method, and it is considered correct and safe, in contrast to deprecated
Thread.Suspend
because it is unsafe, and in contrast to Windows API
TerminateThread
, which is not even included in .NET API. Nevertheless,
you should use this powerful method only if you perfectly understand how it works and what are the possible consequences. There is a class of application where the collaborative termination of the thread is impossible by the nature of the task, then this method is indispensable. If you are not 100% comfortable with this method, you should better use collaborative method: a thread simply exists its main method when the work is done. The other thread can instruct this thread to terminate by passing some request to is, which should be checked by the thread to be terminated periodically. Such
cooperative termination is explained here:
http://msdn.microsoft.com/en-us/library/7a2f3ay4%28v=vs.90%29.aspx[
^].
The method
Thread.Abort
uses
exception seeding. Before .NET emerged, I saw an article from the Microsoft developer who demonstrated the technique on Windows API. Unfortunately, at this moment I don't have my literature references list to find out the original work. The code is platform-dependent, different for different Windows implementations for different
instruction-set architectures, but it is based on documented Windows API. So, how to cause thread termination asynchronously to this thread? The thing is: the threads are scheduled by system scheduler; and their content is stored in the system memory. Windows API has documented access to this storage. So, a terminating thread can pause the thread to be terminated for a short time. The thread context is flashed to the system memory. Then the Instruction Pointer of suspended thread is modified to jump to some code. Of course, when the thread jumps instruction flow to some fixed code fragment, the thread's stack gets messed up. There is only one case when it does not matter. What case? When the fragment of code the thread jumps to never returns but throws exception instead. (To understand it, you should have good understanding on how exceptions work and what they do to the thread's stack.) And what is that exception? Right, this is that very
ThreadAbortException
. I actually implemented such mechanism, that's why I know the detail. This is how it all really works in .NET and other CLR implementations.
Now, being perfectly safe in principle, abortion of the thread is still
unsafe in certain cases. One case is constructing some objects in the thread which can potentially be aborted. The behavior of the code aborted in the state when some objects are "half-constructed" is
unpredictable. Everything has its work-around. You can simply avoid such unsafe operations in a thread which can be aborted, or you can protect it from abortion by avoiding direct abort. You can provide an indirect abort method (still to be called from a different thread) is a thread wrapper interlocked with the
lock
statement, with the possibility to deny or defer abortion in certain critical sections of the code.
[EDIT #1]
Important: In contrast to what would be expected based on common sense, the methods
System.Threading.Thread.BeginCriticalRegion
and
System.Threading.Thread.EndCriticalRegion
do
not provide required protection from the cases I mentioned in the previous paragraph. According to the documentation, they only notify the host that "the effects of a thread abort or unhandled exception might jeopardize other tasks in the application domain". Please see:
http://msdn.microsoft.com/en-us/library/system.threading.thread.aspx[
^] (see
BeginCriticalRegion
),
http://msdn.microsoft.com/en-us/library/system.threading.thread.begincriticalregion.aspx[
^].
You can create a period where the thread spend extended period of time in the critical region and try to abort it from another thread. It will be aborted!
[END EDIT #1]
[EDIT #2]
I also noticed that you use
Thread.IsBackground = true;
and would like to
warn about it. Indeed, the thread marked as a background thread will be terminated automatically after the main thread of the application is terminated; and this is the main difference between a background and non-background thread. It looks convenient and can work, but in most situations it's less predictable the with
Thread.Abort
. There is no a way to terminate a thread at deterministic time, but with cooperative termination or with
Thread.Abort, your can control the order of some of the operations and guarantee that, say, one thread is ready for termination of some other thread. If you leave it uncontrolled relying on the automatic termination of a background thread, order of operations is unpredictable. It still can be used in very simple situation of the end of application lifetime and order of operations and other affected detail is not important. Again, you can only do it if you clearly understand how it works and affects your application termination.
[END EDIT #2]
[EDIT #3]
Please see also my past answer on related topic:
Close correcly the thread inside a dll[
^].
[END EDIT #3]
I did not provide detail of the mechanisms of such advanced method of thread termination and safety measures because I'm not sure you need them. If interested, you are welcome to ask further questions.
—SA