anthonybell
anthonybell

Reputation: 5998

Can I detect a hung process with another thread and recover from it?

I have a method that occasionally hangs (in a dll I cannot modify but must use). If I run it again It will typically work fine. I was wondering if it would be possible to make a background thread that would wait for 20 minutes and then throw an exception in my program.

var triesLeft = 5;
while (triesLeft > 0) {
  try {
    var t = new Thread(() => { wait(20 minutes); throw new ApplicationHungException();})
    t.Start();
    Object o = MethodThatHangsForever10PercentOfTheTime();
  } catch (ApplicationHungException e) {
    triesLeft--;
  }
}
t.Abort();

This does not work because the exception does not pass to the try catch block it's contained in. Is there a way I can get the thread to give it's exception to the try catch block?

Upvotes: 3

Views: 2100

Answers (2)

user1726343
user1726343

Reputation:

One way to do this would be set off your faulty method in the separate thread, and wait for one of two things to happen; either:

  • The thread completes, or
  • A predetermined amount of time (eg 20 mins) elapses

Once either of these things happens, we can take appropriate action.

The code would look something like this:

static void DoProcessing() {
    var triesLeft = 5;
    Object o = null;

    while (triesLeft > 0) {
        var t = new Thread(() => { o = MethodThatHangsForever10%OfTheTime(); }).Start();
        if (t.Join(new TimeSpan(0, 20, 0))) {
            // The thread completed
            break;
        } else {
            // We're out of time.
            t.Abort(); // Important: See comments below about this
            triesLeft--;
        }
    }
}

It turns out that aborting threads is a risky and fragile operation, as pointed out by Reed Copsey in the comments below. Your alternatives are to allow the hung thread to live out the rest of its life (however long that may be), or to quarantine the Heisenbuggy method call to a separate process.

This opens up another can of worms however, since you would have to deal with interprocess communication, data serialization and synchronisation. This may or may not be worth it, which is a judgement call I leave to you.

Upvotes: 3

Reed Copsey
Reed Copsey

Reputation: 564433

You can do your work in a separate thread, and wait 20 minutes for it to complete:

var triesLeft = 5;
while (triesLeft > 0) 
{
    var mre = new ManualResetEvent(false);

    ThreadPool.QueueUserWorkItem(_ => {
                           MethodThatHangsForever10PercentOfTheTime();
                           mre.Set();
                     });

    if (mre.WaitOne(TimeSpan.FromMinutes(20)))
    {
          break; // Success!
    }
    triesLeft--;
  }
}

Upvotes: 2

Related Questions