Welcome to weblogs.com.pk Sign in | Join | Help

.NET 4: Parallel Programming – Cancelling/Exception Handling with Task Parallel Library

There are lot of goodies in .NET 4 for Parallel Programming. There is even a separate dedicated section on it. The following picture from that section explains the four categories of improvement in Framework just for this.

I mentioned earlier that previously I used Abortable Threadpool to implement cancelling work under specific condition. With ThreadPool we never had an easy way to queue the batch of work, know when that batch is completed and do exception handling properly. Things have significantly improved with Task Parallel Library; which is integrated with ThreadPool and resolves all the issues I mentioned plus lot more. Here is small app that does cancelling the tasks after certain time out and investigates the exception if any thrown by the task!

Code:
static Random random = new Random();
static void LongWork(int deviceIdentifier, CancellationToken ct)
{
    var t = Thread.CurrentThread;
    using (ct.Register(t.Abort))
    {
        Thread.Sleep(1000);
        int r = random.Next(5);
        if (ct.IsCancellationRequested)
        {
            Console.WriteLine("{0} cancellation requsted", deviceIdentifier);
            return;
        }
        //Simulating that certain device fails
        if (r > 3)
        {
            string message = string.Format("{0} failed (by random)", deviceIdentifier);
            Console.WriteLine(message);
            throw new ApplicationException(message);
        }
        Thread.Sleep(r * 2000);
        Console.WriteLine("{0} completed", deviceIdentifier);
    }
}

static void Main(string[] args)
{
    var tokenSource = new CancellationTokenSource();
    var token = tokenSource.Token;

    var listOfTasks = new List<Task>();

    for (int i = 0; i < 10; i++)
    {
        int j = i;  //The anonymous delegate will use the latest value by design
        //If we use the for variable value it will always be the last one
        listOfTasks.Add(Task.Factory.StartNew(() => LongWork(j, token), token));
    }

    int seconds = 3;
    //Thread.Sleep(1000);                     //Give the tasks a second to start
            
    Console.WriteLine("{0} Waiting {1}secs", DateTime.Now, seconds);
    Thread.Sleep(seconds * 1000);                           //We have 10secs to do all the tasks
    tokenSource.Cancel(true /*throwOnFirstException*/);     //After that we need to abort uncompleted tasks
    Console.WriteLine("{0} Tasks Cancelled!", DateTime.Now);
    //  If we want we can return/exit here; the cancelled tasks will be taken care
    #region The region is optional; in case we want to know what happened

    var tasks = listOfTasks.ToArray();
    try
    {
        Console.WriteLine("{0} Waiting for Tasks...", DateTime.Now);
        Task.WaitAll(tasks, token);
        //Task.WaitAll(tasks.Where(o => o.Status == TaskStatus.Running).ToArray());
        //may be more optimized version
        Console.WriteLine("{0} Wait completed!", DateTime.Now);
    }
    catch (AggregateException e)
    {
        Console.WriteLine("{0} {1}", DateTime.Now, e.Message);
        foreach (var v in e.InnerExceptions)
        {
            if (!(v is TaskCanceledException))
                Console.WriteLine(v.Message);
            else
                Console.WriteLine("TaskCanceledException expected...");
        }
    }
    catch (OperationCanceledException e)
    {
        Console.WriteLine("{0} {1}", DateTime.Now, e.Message);
    }

    for (int i = 0; i < tasks.Length; i++)
        Console.WriteLine("task[{0}] status is now {1}, IsCancelled={2}", i, tasksIdea.Status, tasksIdea.IsCanceled);

    #endregion

    Console.WriteLine("Press enter to exit!");
    Console.ReadLine();
}


Published Saturday, October 24, 2009 1:45 AM by khurram
Filed under:

Comments

No Comments

New Comments to this post are disabled