Tasks with Timeouts

So the task is to timeout a task. now, I never thought it would take me as long as it did. Turns out it is a really tricky problem problem. I was expecting something within the framework to make life easier, there isn’t anything by default but msdn to the rescue Tasks With Timeout.

So, the extension method is

    public static class TaskWithTimeout
    {
        internal struct VoidTypeStruct
        { }
        internal static void MarshalTaskResults<TResult>(Task source, TaskCompletionSource<TResult> proxy)
        {
            switch (source.Status)
            {
                case TaskStatus.Faulted:
                    proxy.TrySetException(source.Exception);
                    break;
                case TaskStatus.Canceled:
                    proxy.TrySetCanceled();
                    break;
                case TaskStatus.RanToCompletion:
                    Task<TResult> castedSource = source as Task<TResult>;
                    proxy.TrySetResult(
                        castedSource == null ? default(TResult) : // source is a Task
                            castedSource.Result); // source is a Task<TResult>
                    break;
            }
        }
        
        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 static Task<TResult> TimeoutAfter<TResult>(this Task<TResult> 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<TResult> tcs = new TaskCompletionSource<TResult>();

            // 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<TResult>)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;
        }
    }

A lot of code for doing this, and the msdn article remains the better source of explanation.

Now using this.

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>();
			try
			{
//In the continuation check for the condition of fault (or something more if you so need) and perform the //continuation
				var t1 = Task.Factory.StartNew(_ =>	LongRunningTask("Entering task1"),
												    TaskCreationOptions.AttachedToParent)
                                     .TimeoutAfter(1000)
                                     .ContinueWith(antecedent => {
						if(!(antecedent.IsCanceled || antecedent.IsFaulted))
                                                         Output.Add(antecedent.Result);
								}
								, cts.Token);
				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);
                            
                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 important part being that the continuation is applied after the timeout and it won’t work with the other way around.
The output therefore basically looks like this :

In Main
Managed thread Id 9
Entering task1
Managed thread Id 10
Entering task2
Managed thread Id 11
Entering task3
Managed thread Id 14
Adding 194443354 From thread  - 10
Adding 792426557 From thread  - 11
Adding 230130793 From thread  - 14
Output :
792426557
230130793

Next, time I will try and write about some other things on Flirting with Tasks.

Advertisements

Useful Extension Methods

Extension methods provide a very useful way of extending the functionality of a Type (value,reference or interface). The earlier way of extending or rather adding a functionality through inheritance or making an entirely new type from scratch were tedious to say the least.
Extension methods are basically static methods with the calling syntax same as that of static methods. Over the course of the last few weeks i have come to realise they reduce a lot of repetitiveness from the code when used appropriately.MSDN specification also clearly states they must be used sparingly.
So,here are a few useful extension methods.
The syntax has only one new thing, the use of this keyword on the type that the extension method is meant for.

public static XElement ToXElement(this XmlNode node)
{
   var xDoc = new XDocument();
   using (var xmlWriter = xDoc.CreateWriter())
          node.WriteTo(xmlWriter);
   return xDoc.Root;
}

So, calling the code would be something like ,

var xelement = node.ToXElement();

xelement is now an XElement. This might look very plain and simple at the outset but when you really start to have a lot of repetitive functionality over a type this could really bail you out and make the code more readable to say the least. For e.g inside a for loop if you have a lot of code that operates over a type then it could be useful to take it to an extension method and then call the extension method statically.Further, extension methods can also have overloads so that is another nifty feature.
The following extension method returns the XmlAttributeCollection for a XmlNode

 
public static XmlAttributeCollection GetXmlAtrributeCollection(this XmlNode node)
{
    var xmlDoc = new XmlDocument();
    var element = node.ToXElement();
    using (var reader = element.CreateReader())
    {
      xmlDoc.Load(reader);
      return xmlDoc.DocumentElement != null ? xmlDoc.DocumentElement.Attributes : null;
    }
} 

Too much of XML ?? Lets get one really useful extension method.
Lookup is an immutable class in System.Linq. It works similar to a dictionary but does not enforce unique keys , so returns an IEnumerable.
Unfortunately, the creation of a Lookup is internal to .net. So we can only call ToLookup() from a Dictionary etc. So ,i needed some way of adding data to the Lookup.Here is what i came up with.

public class Pairs 
    {
        public String Key { get; set; }
        public Object Value { get; set; }
    }
public static class LookupExtensionMethods
    {
        public static Lookup<String,Object> AddToLookup(this Lookup<String,Object> lookup,
                                                       List<Pairs> pairlist)
        {
            var temp = (Lookup<String, Object>)pairlist.ToLookup(p => p.Key, p => p.Value);
            lookup.Concat(temp);
            return lookup;
        }

        public static Lookup<String, Object> AddToLookup(this Lookup<String, Object> lookup, Pairs pair)
        {
            var pairlist = new List<Pairs> {pair};
            var temp = (Lookup<String, Object>)pairlist.ToLookup(p => p.Key, p => p.Value);
            lookup.Concat(temp);
            return lookup;
        }
    }

Lastly, there is no way to replace the first occurrence of a string in C# straight out of the box(I bet you did not notice that).

 public static string ReplaceFirstOccurrance(this string original, string oldValue, string newValue)
 {
     if (String.IsNullOrEmpty(original))
                return String.Empty;
     if (String.IsNullOrEmpty(oldValue))
                return original;
     if (String.IsNullOrEmpty(newValue))
                newValue = String.Empty;
     var loc = original.IndexOf(oldValue);
     return loc == -1 ? original : original.Remove(loc, oldValue.Length).Insert(loc, newValue);
 }