views:

290

answers:

4

Again I want to talk about safety of the Thread.Abort function. I was interested to have some way to abort operations which I can't control really and don't want actually, but I want to have my threads free as soon as possible to prevent thread thirsty of my application.

So I wrote some test code to see if it's possible to use Thread.Abort and have the aborting thread clean up resources propertly. Here's code:

int threadRunCount = 0;
int threadAbortCount = 0;
int threadFinallyCount = 0;
int iterations = 0;

while( true )
{
 Thread t = new Thread( () =>
 {
  threadRunCount++;
  try
  {
   Thread.Sleep( Random.Next( 45, 55 ) );
  }
  catch( ThreadAbortException )
  {
   threadAbortCount++;
  }
  finally
  {
   threadFinallyCount++;
  }
 } );

 t.Start();
 Thread.Sleep( 45 );
 t.Abort();

 iterations++;
}

So, so far this code worked for about 5 mins, and threadRunCount was always equal to threadFinally and threadAbort was somewhat lower in number, because some threads completed with no abort or probably got aborted in finally.

So the question is, do I miss something?

+1  A: 

Using Thread.Abort is fine. However, it does not always abort immediately. If a thread is doing unmanaged code, it won't actually abort until it returns to managed code.

yu_sha
+1  A: 

Using thread abort is safe enough. However as mentioned by others that a thread abort may not get aborted immediately. Calling thread abort will raise a ThreadAbortException in the thread. To clean up resources you can catch this exception and do the necessary cleanups.

static void Run()
{
  try 
  {
    while(someCondition)
    {
       ....
       ....
       ....
       if (someOtherCondition)
          throw new ThreadAbortException("Thread aborted");
    }
  }
  catch(ThreadAbortException e)
  {
    ...
    ... //clean up resources here.
    ...
  }
  finally
  {
    ...
  }  
}
S M Kamran
The second you introduce resources that needs cleanup into your thread, Thread.Abort is *not* safe enough.
Lasse V. Karlsen
+1  A: 

With a contrived test, you can prove anything.

All you have proved is that with the code you wrote for your test, Thread.Abort seems to work fine.

The problem is, however, that as soon as you start using things that needs to be disposed of, all hope is lost.

For instance, try this code:

using (Stream stream = new FileStream(@"C:\Test.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None))
{
    Thread.Sleep( Random.Next( 45, 55 ) );
}

Now, run this for a while and tell me if that still works.

The problem appears when the code has left your sleep-call, and is inside the implicit finally-block for the using-block, and is just about to close your stream, and then you abort it.

The problem with Thread.Abort is that it can happen anywhere, even within code that isn't supposed to throw exceptions.

For instance, do you really expect the following code to crash after the if-expression has been evaluated, but before the Dispose-call has gone through?

if (_ObjectToDispose != null)
{
    _ObjectToDispose.Dispose();
    _ObjectToDispose = null;
}

What if it happens right after the call to .Dispose? The field will still have a non-null value, which could lead to subtle problems elsewhere.

What if you do this:

IDisposable objectToDispose = Interlocked.Exchange(ref _ObjectToDispose, null);
if (objectToDispose != null)
    objectToDispose.Dispose();

With this code, you grab the value, replaces it with null, and then before you get around to calling Dispose, your ThreadAbortException happens, which will just leave the object.

Let me just drive the point home:

Thread.Abort should never be used, except in scenarios where you need to terminate the program (or tear down a custom AppDomain with threads running in it). You should never call Thread.Abort and then continue running.

Unless you need to plan bugs into your future schedule. In that case, go right ahead and use Thread.Abort, because I can almost guarantee you will have problems.

Lasse V. Karlsen
I tried to run code you mentioned with file opening, and yes at some point after new thread's being created file is still busy with another thread which should be aborted really, but what if threads won't use shared resources? Seems it just proves that thread Abort is somewhat not safe.Even if I just need to terminate application couldn't Abort lead to process hang or some memory leak if some unmanaged code was running?In my case I needed something that can limit process running time to exact timeout limit, and in my case I can't control this process execution. Any ideas on this case?
hoodoos
You should pose a different question on SO, how to limit execution time, and then post what you intend to do in that code. In some cases, it won't be possible to do what you want if the code is busy in unmanaged code, as an example. The only "safe" way to do that would be to spawn a sub-process that terminates completely after the timeout has elapsed.
Lasse V. Karlsen