2

This is not about terminating a system-process but killing "myself". I have several parallel theads, which CAN hang because of different reasons.

I already created a watchdog when a thread is taking too long:

TimerCallback timerDelegate = new TimerCallback(CheckProcessStatus);
System.Threading.Timer watchDogTimer = new Timer(timerDelegate, new ProcessHealth(plog), 1000 * 60, 1000 * 60);
try
   {
   // lots of code here
   } finally
   {
      watchDogTimer.Dispose();
   }

Watchdog:

public void CheckProcessStatus(Object timerState) {
    ProcessHealth ph = (ProcessHealth)timerState;
    System.writeLine(string.Format("process runs for {0} minutes!", ph.WaitingTime);
    if (ph.WaitingTime>60) {
      // KILL THE PROCESS
    }
}

When "lots of code here" takes too long I want to terminate the thread no matter what state it is in. (at "Kill the process").

What would be the best approach?

Thread.CurrentThread.Interrupt()

OR

Thread.CurrentThread.Abort()?

Or are there even better approaches? (I cannot use "simple" mechanisms like boolean "stop"-variables as the "lots of code here" is VERY Dynamic calling other classes via reflection etc.

Does that even work? Or do I just kill the watchdog-thread, NOT the thread to be watched?

usr
  • 168,620
  • 35
  • 240
  • 369
Ole Albers
  • 8,715
  • 10
  • 73
  • 166
  • throw an exception? "goto" end of your threadFunc seems better than brutally killing the thread. – Ventsyslav Raikov Jun 01 '12 at 12:32
  • Semi-related: http://stackoverflow.com/q/10827930/15541 (guess you can adjust for multiple threads) – leppie Jun 01 '12 at 12:36
  • 1
    Environment.FailFast() is a very effective way to end the misery. Doing anything like aborting threads is just heaping more bugs on top of the ones you already got. – Hans Passant Jun 01 '12 at 12:38
  • possible duplicate of [Question about terminating a thread cleanly in .NET](http://stackoverflow.com/questions/3632149/question-about-terminating-a-thread-cleanly-in-net) – Jerod Venema Jun 01 '12 at 12:38
  • the volatile bool approach does not fit (like i wrote in the last passage) – Ole Albers Jun 01 '12 at 12:40
  • @Bond Would throwing an exception not terminate the Timer thread instead of the worker thread? – Ole Albers Jun 01 '12 at 12:59

2 Answers2

3

Aborting a thread, when it is in an unknown state, is not advisable. Say, the thread is currently executing a static constructor. The static ctor will be aborted and never run again (because faulting static ctor's never run again). You have effectively destroyed global state in your AppDomain without a way to ever recover.

There are lots of other hazards as well. That just doesn't fly.

There are two production-ready choices aborting threads:

  1. Cooperatively (set an event or a boolean flag in combination with Thread.MemoryBarrier)
  2. Don't abort the thread, but the entire AppDomain or process. Thread level granularity is too small. You need to delete all state related to that thread, doo.

I want to stress that you cannot make this work any other way. You will have the strangest faults in production if you insist on aborting threads non-cooperatively.

usr
  • 168,620
  • 35
  • 240
  • 369
  • I usually would agree but this is a service that has to run massivly parallel threads. This works very fine, but from time to time a thread just hangs once in a month. We catch all exceptions and even know in which line it happens, but cannot avoid that behaviour. I know I am searching for a dirty solution but have no choice Also: Thread granularity is ok in our case as the Threads are dynamicly started by Database-Entries creating objects by reflection. So these Threads are completely seperated. – Ole Albers Jun 01 '12 at 13:40
  • @OleAlbers - It seems you are trying to solve the wrong problem. Instead of solving the reason your thread hangs your trying to solve the "how to kill the hanged thread" problem. – Security Hound Jun 01 '12 at 13:52
  • 1
    Ok, if you know the code that is running you can safely kill the thread because it is cooperative that way. Use Interrupt to break pending synchronizations and About for everything else. Maybe you could post the code that is hanging? – usr Jun 01 '12 at 14:01
3

Thread.Abort attempts to terminate the target thread by injecting an out-of-band (asynchronous) exception. It is unsafe because the exception gets injected at unpredictable points in the execution sequence. This can (and often does) lead to some type of corruption in the application domain because of interrupted writes to data structures.

Thread.Interrupt causes most blocking calls in the BCL (like Thread.Sleep, WaitHandle.WaitOne, etc.) to bailout immediately. Unlike aborting a thread, interrupting a thread can be made completely safe because the exception is injected at predictable points in the execution sequence. A crafty programmer can make sure these points are considered "safe points".

So, if "lots of code here" will respond to Thread.Interrupt then that might be an acceptable approach to use. But, I would like to steer you more towards the cooperative cancellation pattern. Basically, this means your code must periodically poll for a cancellation request. The TPL already has a framework in place for doing this via CancellationToken. But, you could easily accomplish the same thing with a ManualResetEvent or a simple volatile bool variable.

Now, if "lots of code here" is not under your control or if the cooperative cancellation pattern will not work (perhaps because you are using a faulty 3rd party library) then you pretty much have no other choice but to spin up a completely separate process to run the risky code. Use WCF to communicate with the process and if it does not respond then you can kill it without corrupting the main process. It is a lot of work, but it may be your only option.

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150