I wanted to have a series of tasks being executed each with a timeout of it's own.
I borrowed the extension method for creating tasks with timeouts from here http://blogs.msdn.com/b/pfxteam/archive/2011/11/10/10235834.aspx
So the code is below
public static Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
// Short-circuit #1: infinite timeout or task already completed
if (task.IsCompleted || (millisecondsTimeout == Timeout.Infinite))
{
// Either the task has already completed or timeout will never occur.
// No proxy necessary.
return task;
}
// tcs.Task will be returned as a proxy to the caller
TaskCompletionSource<VoidTypeStruct> tcs = new TaskCompletionSource<VoidTypeStruct>();
// Short-circuit #2: zero timeout
if (millisecondsTimeout == 0)
{
// We've already timed out.
tcs.SetException(new TimeoutException());
return tcs.Task;
}
// Set up a timer to complete after the specified timeout period
Timer timer = new Timer(state =>
{
// Recover your state information
var myTcs = (TaskCompletionSource<VoidTypeStruct>)state;
// Fault our proxy with a TimeoutException
myTcs.TrySetException(new TimeoutException());
}, tcs, millisecondsTimeout, Timeout.Infinite);
// Wire up the logic for what happens when source task completes
task.ContinueWith(antecedent =>
{
timer.Dispose(); // Cancel the timer
MarshalTaskResults(antecedent, tcs); // Marshal results to proxy
},
CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
return tcs.Task;
}
public class Program
{
private static List<int> Output = new List<int>();
private static Random _random = new Random();
public static void LongRunningTask(string message)
{
Console.WriteLine(message);
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
//Simulate a long running task
Thread.Sleep(TimeSpan.FromSeconds(3));
var number = _random.Next();
Console.WriteLine("Adding " + number);
Output.Add(number);
}
public static void Main(string[] args)
{
var tasks = new List<Task>();
var t1 = Task.Factory.StartNew(_ => LongRunningTask("Entering task1"),TaskCreationOptions.AttachedToParent).TimeoutAfter(10);
var t2 = Task.Factory.StartNew(_ => LongRunningTask("Entering task2"),TaskCreationOptions.AttachedToParent);
var t3 = Task.Factory.StartNew(_ => LongRunningTask("Entering task3"),TaskCreationOptions.AttachedToParent);
tasks.Add(t1);
tasks.Add(t2);
tasks.Add(t3);
try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("There was an exception");
Console.WriteLine(ex.InnerException.Message);
}
Console.WriteLine("Output :");
Output.ForEach(_ => Console.WriteLine(_));
Console.ReadLine();
}
}
the output
Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 14
Adding 453738994
Adding 156432981
Adding 1340619865
There was an exception
The operation has timed out.
Output :
453738994
156432981
1340619865
Now, what I can't understand is why is the t1 still finishing even though I have specified a timeout and the timeout exception has occurred.
I am using .net 4.
Edit :
Ensuring that the timed out task doesn't do anything after the timeout period i.e. cancelling the task altogether.
public class Program
{
private static List<int> Output = new List<int>();
private static Random _random = new Random();
public static int LongRunningTask(string message)
{
Console.WriteLine(message);
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
//Simulate a long running task
Thread.Sleep(TimeSpan.FromSeconds(2));
var number = _random.Next();
Console.WriteLine("Adding " + number + " From thread - " + Thread.CurrentThread.ManagedThreadId);
return number;
}
public static void Main(string[] args)
{
Console.WriteLine("In Main");
Console.WriteLine("Managed thread Id " + Thread.CurrentThread.ManagedThreadId);
var cts = new CancellationTokenSource();
var tasks = new List<Task>();
var t1 = Task.Factory.StartNew(_ => LongRunningTask("Entering task1"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result),cts.Token)
.TimeoutAfter(1000);
var t2 = Task.Factory.StartNew(_ => LongRunningTask("Entering task2"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result));
var t3 = Task.Factory.StartNew(_ => LongRunningTask("Entering task3"), TaskCreationOptions.AttachedToParent)
.ContinueWith(_ => Output.Add(_.Result));
tasks.Add(t1);
tasks.Add(t2);
tasks.Add(t3);
try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
Console.WriteLine("There was an exception");
Console.WriteLine(ex.InnerException.Message);
cts.Cancel();
}
Console.WriteLine("Output :");
Output.ForEach(_ => Console.WriteLine(_));
Console.ReadLine();
}
}
Output :
In Main
Managed thread Id 9
Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 13
Adding 1141027730 From thread - 10
Adding 1856518562 From thread - 13
Adding 1856518562 From thread - 11
There was an exception
The operation has timed out.
Output :
1141027730
1856518562
1856518562