Working with Tasks in .NET Framework 4.0 - An Insight

The .Net framework 4.0 version is mounted with lots of new features, out of which the Parallel Programming using the Task Parallel Library (TPL) is the one gaining more interest. In this article I will write about the Task class under the namespace System.Threading.Tasks. The asynchronous operations scheduled through a Task class make sure that the system resources are used intelligently, such as scheduling the threads on different cores available on the processor; it also provides a lot of control over the scheduled tasks, like fetching the return value, cancelling a task, building nested tasks, etc.

Starting a Parallel Task

In this section let us see the various ways of starting the tasks. A Task class can be directly instantiated and started like that of a Thread class. Below is the sample code.

    static void Main(string[] args)
    {
        Task task1 = new Task(PrintA5Times);
        task1.Start();
        Console.ReadLine();
    }

In the above code a task is created when Task class is instantiated and only gets scheduled when the Start method is called. A task scheduler takes care of loading these tasks onto different threads. There is a factory class available, which can be used to create the task and schedule it instantly.

    static void Main(string[] args)
    {
        Task.Factory.StartNew(() =>
            {
                Console.WriteLine("This task is created and scheduled through task factory!");
            });
 
        Console.ReadLine();
    }

Synchronizing Tasks

When dealing with asynchronous operations, the most important thing is to know about the synchronization techniques. Below are the different ways to synchronize tasks.

Wait

Wait is an instance method available in the Task object. Calling this method only blocks the actual task until the task is completed or until a specified timeout.

    static void Main(string[] args)
    {
        Task task1 = new Task(PrintA1000Times);
        task1.Start();
        Task task2 = new Task(PrintB500Times);
        task2.Start();
 
        //Perform other operations
            
        //Wait for task1 to complete
        task1.Wait();
        Console.WriteLine("Task1 completed!");
 
        //Perform some more operations
 
        //Wait for task2 to complete with a time out
        task2.Wait(10000);
        if(task2.IsCompleted)
            Console.WriteLine("Task2 completed!");
        else
            Console.WriteLine("Task2 Timed out!");
 
        Console.ReadLine();
    }

WaitAll

WaitAll is a static method in the Task class and it can be used to synchronize all of the tasks. This method call will make the execution wait until all of the scheduled tasks are completed.

    static void Main(string[] args)
    {
        Task task1 = new Task(PrintA1000Times);
        task1.Start();
        Task task2 = new Task(PrintB500Times);
        task2.Start();
        Task task3 = new Task(SleepFor1Min);
        task3.Start();
 
        Task.WaitAll(task1, task2, task3);
        Console.WriteLine("All the tasks completed!");
 
        Console.ReadLine();
    }

WaitAny

This is again a static method in the Task class and it makes the execution wait until any one of the task is completed.

    static void Main(string[] args)
    {
        Task task1 = new Task(SleepFor3Min);
        task1.Start();
        Task task2 = new Task(SleepFor2Min);
        task2.Start();
        Task task3 = new Task(SleepFor1Min);
        task3.Start();
 
        int taskIndex = Task.WaitAny(task1, task2, task3);
        Console.WriteLine("Task with index {0} is completed", taskIndex);
 
        Console.ReadLine();
    }

Dependent Tasks

You can also create dependent Tasks by either attaching the child task to a parent task or by specifying a task to be scheduled only when the dependent task operation is completed.

ContinueWith

The ContinueWith method creates a new task and schedules it once the dependent task is completed. Below is the example demonstrating it.

    static void Main(string[] args)
    {
        Task<int> task1 = new Task<int>(GetTotal);
        task1.Start();
        Task task2 = task1.ContinueWith(task => PrintTotal(task.Result));
 
        Console.ReadLine();
    }

AttachToParent

This attaches the child task to the parent so a Wait method call on the parent task will be released only if the child task is completed. Below is an example.

    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() =>
            {
                PrintA10Times();
                Task task2 = new Task(SleepFor1Min, TaskCreationOptions.AttachedToParent);
                task2.Start();
            });
 
        task1.Wait();
        Console.WriteLine("Both parent and child tasks are completed!");
 
        Console.ReadLine();
    }

Cancellation of Tasks

In this section let us look at an example where a task can be cancelled. The basic idea is to pass the token value from the CancellationTokenSource object to the Task while creating it and when the Cancel method of the TokenSource is called, the corresponding Task is cancelled.

    static void Main(string[] args)
    {
        CancellationTokenSource tokenSource = new CancellationTokenSource();
        Task task1 = new Task(SleepFor2Min, tokenSource.Token);
 
        //Wait for some time
        task1.Wait(1000);
        //Cancel the task
        tokenSource.Cancel();
 
        Console.WriteLine("Status of task1: {0}", task1.Status);
 
        
        Console.ReadLine();
    }

There many more things that you can accomplish using the Task class that the .net framework 4.0 has provided as a part of Task Parallel Library. With this insight on tasks I leave it to the user to explore more.

Happy reading!



Related Articles

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's competitive marketplace requires the organization to frequently release and deploy applications at the pace of user demands, with reduced cost, risk, and increased quality. This book defines the basics of application release and deployment, and provides best practices for implementation with resources for a deeper dive. Inside you will find: The business and technical drivers behind automated application release and deployment. Evaluation guides for application release and deployment solutions. …

  • On Demand Webcast It's complicated. We're connected to multiple devices, and those devices are connected to other devices, which are connected to systems connected to other systems. And as a result of this global interconnectivity, we are generating an abundance of unstructured data, which in turn must be stored and made accessible so we can use it. This phenomenon, known as the "Internet of Things" (IoT) is fueling the proliferation of Big Data; it's also changing the way we work. Not surprisingly, IoT and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds