Asynchronous Programming in C# 5.0: Part Three: Understand Task in Asynchronous Programming

Welcome to the Asynchronous Programming in C# 5.0 article series. The previous two articles erxplained what asynchronous programming is and how to implement it in C# 5.0. We also have seen various return types of asynchronous functions. To read all those, please visit the following links.

  1. Asynchronous programming in C# 5.0: Part-1: Understand async and await 

  2. Asynchronous Programming in C# 5.0 Part 2: Return Type of Asynchronous Method

This article explains Tasks in asynchronous programming. If we follow the previous two articles (or if you are already familiar with Tasks) then you will find that we are returning a Task from an asynchronous function. But the question is, what is a Task? Let me give a single-line answer: "A Task is a basic unit of the Task Parallel Library (TPL)". I know that that single-line answer is not enough for understanding what a Task is. Don't worry; we will dig into it more since this article is dedicated to Tasks. (Not office tasks, Tasks of asynchronous programming!!) Ok, let's be serious and proceed to the topic.
So, a Task is nothing but a unit of work. Try to map them with real life task to understand better.

  • Task can run/start: Real-life tasks can run/start (read proceed).
  • Task can wait: Real-life tasks wait too (my friend waited for seven days to get feedback of his first proposal, though it was negative.)
  • Task can cancel: No need to provide an example, you often cancel your task.
  • Task can have a child Task: Yes, there are subtasks in people's lives.

So, those are the features (better to say properties) of Tasks in asynchronous programming. A Task can only run from its start to its finish, you cannot run the same task object two times. Now , the question is , what is the solution for running the same task more than once? The answer is you will need to create another Task object to run the same task.

Ok, let's try one small example to understand Tasks.

Have a look at the following code. Here we will create an object of the Task class.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Asynchronious

{

    class Program

    {

        public static void Main(String [] args)

        {

            Task t = new Task(

                () => {

                       System.Threading.Thread.Sleep(5000);

                       Console.WriteLine("Huge Task Finish"); 

                     }

                );

 

            //Start the Task

            t.Start();

            //Wait for finish the Task

            t.Wait();

            Console.ReadLine();

        }

    }

}

We are calling the Start() method to start the Task. After that we are calling the Wait() method that implies that we are waiting for the task to finish. Here is sample output.

Asynchronous1.jpg

How to Wait for a Task?

Let's try to understand how to delay (or sleep) a Task for a while. Have a look at the following example.
 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace Asynchronious

{

    class Program

    {

        public static void Main(String [] args)

        {

            Task t = new Task(

                () => {

                       System.Threading.Thread.Sleep(5000);

                       Console.WriteLine("Huge Task Finish"); 

                     }

                );

 

            //Start the Task

            t.Start();

            //Wait for 1 second

            bool rValue = t.Wait(1000);

            Console.WriteLine("Main Process Finished");

            Console.ReadLine();

        }

    }

}


In this example we are waiting to finish a huge task for one second even after it has actually finished. So, we learn how to continue to wait for a Task. Here is the output screen.

Asynchronous2.jpg

Implement Child Task

Here we will implement a child Task of another Task. Have a look at the following code.
 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace Asynchronious

{

    class Program

    {

        public static void Main(String [] args)

        {

            Task Parent = new Task(

                () => {

                       Task Child = new Task(

                        ()=> {

                                System.Threading.Thread.Sleep(2000);

                                Console.WriteLine("Inner Task Finish"); 

                            },

                            TaskCreationOptions.AttachedToParent

                        );

                       

                       //Start Child Task

                       Child.Start();

                       System.Threading.Thread.Sleep(2000);

                       Console.WriteLine("Outer Task Finish");

                     }

                );

 

            //Start the Task

            Parent.Start();

            Parent.Wait();

 

 

            Console.ReadLine();

        }

    }

}


At first we created a Parent Task that contains another child Task within it. The innermost and outermost Tasks will sleep for two seconds. We are running a child Task within the object of a parent Task.

Asynchronous3.jpg

Now, let's analyze the output. We see that at first the outer Task is finishing and then the innermost Task finishes. Why is that? It is happening due to an asynchronous call. The outer Task is running the innermost Task but not waiting for it and this is the beauty of an asynchronous call.

Get Status of Task

We can detect the status of any Task. Let's see in the following example.
 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

namespace Asynchronious

{

    class Program

    {

        public static void Main(String [] args)

        {

            Task t = new Task(

                                () => {

                                    System.Threading.Thread.Sleep(5000);

                                   

                                });

 

            t.Start();

            t.Wait();

            Console.WriteLine(t.Status);

            Console.WriteLine("End of Main");

            Console.ReadLine();

        }

    }

}


Here we are starting the Task and then we are waiting for the Task to be complete. In the next line we are checking the Status of the Task using the Status property of the t (Task) object. Now a question may arise. What is the purpose of checking the status? There are many things to do, so we can run another Task depending on the status of another Task. Let's see the output.

Asynchronous4.jpg

The status is showing RunToCompletion. It means that the Task is running currently and it will complete.

Few more properties of Task class

Let's check a few more properties of the Task class. Have a look at the following example.
 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

namespace Asynchronious

{

    class Program

    {

        public static void Main(String [] args)

        {

            Task t = new Task(

                                () => {

                                    System.Threading.Thread.Sleep(5000);

                                   

                                });

 

            t.Start();

            Console.WriteLine("Cancelled:- " +  t.IsCanceled);

            Console.WriteLine("Completed:- " + t.IsCompleted);

            Console.WriteLine("Folted:- " +  t.IsFaulted);

            Console.WriteLine("End of Main");

            Console.ReadLine();

        }

    }

}


Here we will check a few statuses of the Task object. For example we are interested in checking for the Cancel, Completed and Failed statuses of the Task. In the example all are False. That means

  • Cancelled: The Task is not Cancelled

  • Completed: It is not completed (still running)

  • Faulted: There is no error or exception to run this Task.

    Asynchronous5.jpg

Conclusion

In this article we have learned what a Task is and various properties of Task. In future articles we will concentrate on exception handling in asynchronous programming. Keep on reading this series. Hey..!! Are you still reading? Then that means both of us love asynchronous programming. Have a nice day.

<<Previous article                                                      Next article >>