Sam
Sam

Reputation: 731

Operation Timeout TPL

I need to monitor a task and kill it if it takes longer than a defined timeout.

So far, I had many attempts that started with creating a thread and issuing a thread abort, etc. Then, I decided to use TPL.

You have to assume that WorkItem is a black box. You don't have access to its source code. So, rewriting it to have it keep track of a token is not realistic. This needs to be controlled from out side.

Any ideas?

  public class WorkItem : IDisposable
  {
    private System.Diagnostics.Stopwatch _watch = new System.Diagnostics.Stopwatch();
    private List<string> _messages = new List<string>();

    public void WriteMessage(string message)
    {
      _messages.Add(message);
    }

    public void Run()
    {
      for (int i = 1; i <= 25; i++)
      {
        System.Threading.Thread.Sleep(1000);
        Console.WriteLine("Slept one second after {0} iteration.", i);
      }
    }

    public void Dispose()
    {
      _watch.Stop();
      Console.WriteLine("Disposed... lived for {0} milliseconds", _watch.ElapsedMilliseconds);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      int timeout = 5000;
      WorkItem item = new WorkItem();
      System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew<WorkItem>((arg) =>
      {
        WorkItem currentWorkItem = arg as WorkItem;
        currentWorkItem.Run();
        return currentWorkItem;
      }, item);

      bool wait = task.Wait(timeout);
      if (wait == false)
      {
        Console.WriteLine("It took more than {0} ms.", timeout);
        // Need a way to kill the task.
      }

      Console.WriteLine("Okay Waiting");
      Console.ReadKey();
    }
  }

Upvotes: 0

Views: 224

Answers (1)

Jim Mischel
Jim Mischel

Reputation: 134035

There's a reason that Task doesn't have a way for you to cancel it externally. When you have a black box running, there's no telling what it might be doing when you kill it. It could be holding locks. It could be in the middle of modifying some shared state. It could be doing any number of things that, if interrupted, will leave your program in an unknown and very likely corrupt state. Aborting a thread is like just turning off your computer's power switch. There's no telling what you might destroy.

I very strongly recommend against what I'm about to suggest, but if you really absolutely must under pain of death or losing your job shoot yourself in the head ... errrr, give your program the ability to kill your black box, then do it with a thread.

WorkItem threadResult = null;
Thread t = new Thread((arg) =>
    WorkItem currentWorkItem = arg as WorkItem;
    currentWorkItem.Run();
    threadResult = currentWorkItem;
  }, item);

// wait for thread to exit
bool done = t.Join(timeout);            
if (!done)
{
    t.Abort();
}

Once again, I disavow responsibility for any negative consequences you may experience as a result of using this technique. Aborting threads will almost always get you into trouble down the road.

Upvotes: 3

Related Questions