Safely stop long running task
c#, task-parallel-library, timeout
Solution
Here is an example for option 1 described obove ( i.e. just killing the Task without signalling cancellation)
class Program
{
private static void Main(string[] args)
{
Test test = new Test();
test.Run();
Console.WriteLine("Type c to cancel");
if (Console.ReadLine().StartsWith("c"))
{
Console.WriteLine("cancellation requested");
test.CancellationTokenSource.Cancel();
}
Console.ReadLine();
}
}
public class Test
{
private void DoSomething()
{
Console.WriteLine("DoSomething runs for 30 seconds ");
Thread.Sleep(new TimeSpan(0, 0, 0, 30));
Console.WriteLine("woke up now ");
}
public CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
public void Run()
{
var generateReportsTask = Task.Factory.StartNew(() =>
{
CancellationTokenSource.Token.ThrowIfCancellationRequested();
Task doSomething = new Task(DoSomething, CancellationTokenSource.Token);
doSomething.Start();
doSomething.Wait(CancellationTokenSource.Token);
}, CancellationTokenSource.Token);
generateReportsTask.ContinueWith(
(t) =>
{
if (t.Exception != null)
Console.WriteLine("Exceptions reported :\n " + t.Exception);
if (t.Status == TaskStatus.RanToCompletion)
Console.WriteLine("Completed report generation task");
if (t.Status == TaskStatus.Faulted)
Console.WriteLine("Completed reported generation with unhandeled exceptions");
if(t.Status == TaskStatus.Canceled)
Console.WriteLine("The Task Has been cancelled");
});
}
}
Problem
How can I stop a long running task (.net 4)? I have implemented TPL and tried using the `CancellationTokenSource` but it doesn’t seem to work for my scenario. All examples I’ve seen assume you’re doing work in a while-loop so that you can check if the task has been cancelled, whereas I just have a single operation that takes long. I cannot wait for the work to be completed as I need to assume it might never complete. Here is the code I have tried: ``` bool? result = null; var cs = new CancellationTokenSource(); var ct = cs.Token; var doWorkTask = new Task(() => { Console.WriteLine("start dowork task"); result = Work.LongRunning(); }, ct); doWorkTask.Start(); Task.WaitAny(new Task[] { doWorkTask }, timetowait); if (doWorkTask.IsCompleted) { Console.WriteLine("dowork task completed"); doWorkTask.Dispose(); } else { Console.WriteLine("dowork task has timedout"); cs.Cancel(); throw new TimeoutException("Timeout hit."); } ``` The code works but the task is never disposed if the timeout happens and the work that is being done accesses 'unmanaged code' i.e. resources. That said the `IsCancelledRequested` cannot be used in `Work.LongRunning()` so I cannot `ThrowIfCancellationRequested`. I am open to other ideas as well as I have tried `BackgroundWorker` but that also doesn’t seem to fit. New example: ``` var service = new System.ServiceProcess.ServiceController(ServiceName, ServerName); var serviceTask = Task.Factory.StartNew(() => { result = (service.Status == ServiceControllerStatus.Running || service.Status == ServiceControllerStatus.StartPending); }, cs.Token); serviceTask.Wait(2000, cs.Token); if (!serviceTask.IsCompleted) { cs.Cancel(); } ```