Tasks in C# is an object representing an operation or work that executes in asynchronous manner. It was introduced in .NET framework 4.0 to support asynchronous programming.
It’s a basic component of the Task Parallel Library (TPL) and is mostly used for asynchronous programming and parallel processing. In this blog, we will explore more details regarding Task and its usage.
What is a Task in C#?
In C#, Task is basically used to implement asynchronous programming model, the .Net runtime executes a Task object asynchronously on a separate thread from the thread pool.
- Whenever you create a Task, the TPL (Task Parallel Library) instructs the Task Scheduler to execute the operation in a separate thread.
- The Task Scheduler is responsible to execute the Task, by default it requests a worker thread from the Thread Pool to execute the Task.
- Here, the thread pool manager determines whether to create a new thread or reuse an existing thread from the thread pool to execute the operation.

The TPL abstracts the complexity of managing threads and synchronization, it allows you to focus on defining tasks and the high-level structure of their asynchronous code.
Creating Tasks in C#?
To create a Task in C#, first you need to import System.Threading.Tasks namespace into your program, then you can use the Task class to create object and access its properties.
1 2 3 4 |
//Create a task instance Task t = new Task(PrintEvenNumbers); //Start the task t.Start(); |
Example – 1: Creating Tasks in C# using Task class and Start method.
In below example,
- We have created a Task object as Task t , passing the method PrintEvenNumbers in the constructor.
- Finally, we invoke the Task t by t.Start() method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using System; using System.Threading; using System.Threading.Tasks; namespace TaskInCshap { class Program { static void Main(string[] args) { Console.WriteLine("Intiate the Main program in thread : {0} " , Thread.CurrentThread.ManagedThreadId); //Create a task instance Task t = new Task(PrintEvenNumbers); //Start the task t.Start(); Console.Read(); } public static void PrintEvenNumbers() { Console.WriteLine("Intiate the Task PrintEvenNumbers in a separet thread : {0} ", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Even numbers less than 10"); for (int i = 0; i <= 10; i++) if (i % 2 == 0) Console.WriteLine("Number : {0}", i); } } } |
When we run above example, it generates below output.

The output clearly demonstrates that the Main program executes in thread number: 1 and the Task executes in a separate thread having thread number as 3.
Different ways of creating Tasks in C#:
There are various ways available in C#.Net 4.0 to create a Task object. Please find some of the different ways as follows.
1) Task creation using Factory method: You can use Task.Factory() method to creates a Task instance and invoke it in a single line of code, as follows.
1 2 |
//Create a task and invoke it Task.Factory.StartNew(PrintEvenNumbers); |
2) Task creation using Action Generic Delegate: You can use below syntax to create a Task using Action type (Generic Delegate).
1 2 3 4 |
//Create a Task using Action delegate Task t = new Task(new Action(PrintEvenNumbers)); //Invoke Task t.Start(); |
3) Task creation using a Delegate: In below code sample, we are using delegate keyword to create a Task instance and then invoking it.
1 2 3 4 |
//Create a Task using delegate Task t = new Task(delegate { PrintEvenNumbers(); }); //Invoke Task t.Start(); |
Similarly, we can also use Task.Run() method to create a Task object and invoke it in single line, as follows.
1 2 |
//Invoke it directly using Run method Task t = Task.Run(delegate { PrintEvenNumbers(); }); |
4) Task creation using Lambda and named method: In below code sample, we are using lambda and named method expression to create a Task instance and then invoking it.
1 2 3 4 |
//Creating a Task instance using lambda and named method Task t = new Task(() => PrintEvenNumbers()); //Invoke Task t.Start(); |
Similarly, we can also use Task.Run() method to create a Task object and invoke it in single line, as follows.
1 2 |
//Invoke it directly using Run method Task t = Task.Run(() => PrintEvenNumbers()); |
Example – 2: Example of a Task creation and execution flow
Let’s go through an example and see the Task creation and execution in detail.
In below example,
- We have created a method as PrintOddEvenNumbers that prints odd and even numbers.
- In the Main method, we have created a task instance Task t = new Task(PrintOddEvenNumbers); , assigned it to the method and then invoking it by calling t.start() .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; using System.Threading.Tasks; namespace TaskInCshap { class Program { static void Main(string[] args) { //Creating a Task instance using lambda and named method Task t = Task.Run(() => PrintOddEvenNumbers()); Console.WriteLine("In Main Method, Finished work on thread : {0}", System.Threading.Thread.CurrentThread.ManagedThreadId); Console.Read(); } public static void PrintOddEvenNumbers() { Console.WriteLine("Even and Odd numbers less than 10"); //Print even numbers for (int i = 0; i <= 10; i++) if(i%2 == 0) Console.WriteLine("Even Number : {0}", i); //Print odd numbers for (int i = 0; i <= 10; i++) if (i % 2 != 0) Console.WriteLine("Odd Number : {0}", i); Console.WriteLine("In Child Method, Finished work on thread : {0}", System.Threading.Thread.CurrentThread.ManagedThreadId); } } } |
When we run above example, it generates below output.
- If you look at the console output, once the Task executes successfully, it prints odd and even numbers less than 10 on the console window.

In the above output window, if you look at the messages, then it’s clear that the Task executed on a separated Child thread (Thread Number: 3), whereas Main method executed on main thread (Thread ID : 1).
Also, if you observe above result,
- Both threads (Main and Child) started its execution simultaneously (asynchronously), however the Main thread didn’t wait for the Child thread to complete.
- The Child thread continued its execution until it finishes its task even after completion of Main thread execution.
If you want to make the Main thread execution to wait until the other tasks complete its execution, you can do that by using Task.Wait method. To know more about this, please check my next article Tasks in C# Extended.
Key Points of Tasks in C#:
Following are some of the key points that you need to remember about Tasks.
- You can use Task to run multiple operations concurrently, using Task you can continue executing other tasks or operations while the Task runs in the background.
- If a Task produces a result, you can access it using the Result property, however this can cause blocking if the task isn’t completed.
- You can chain tasks together using continuations, specifying what should happen next when a Task completes, enhancing workflow control.
- Exceptions thrown within a Task are captured and stored until the task is awaited or observed. You should handle exceptions explicitly using try and catch blocks.
- You can gracefully cancel a Task using cancellation tokens, which is useful for managing tasks that may take a longer time.
Conclusion:
In conclusion, a Task in C# helps you manage asynchronous and parallel programming, it makes your program more responsive and efficient when dealing with time-consuming operations. Please check our next article here on below topic.
- How to wait for Task to complete?
- Get return value from Tasks?
Very helpful blog 👍
Amazing explanation Task article.