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.
Task_In_C_Sharp
Task_In_C_Sharp

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.

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.

When we run above example, it generates below output.

Tasks in C# OutPut 1.0
Tasks in C# OutPut 1.0

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.

2) Task creation using Action Generic Delegate: You can use below syntax to create a Task using Action type (Generic Delegate).

3) Task creation using a Delegate: In below code sample, we are using delegate keyword to create a Task instance and then invoking it.

Similarly, we can also use Task.Run() method to create a Task object and invoke it in single line, as follows.

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.

Similarly, we can also use Task.Run() method to create a Task object and invoke it in single line, as follows.

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() .

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.
Tasks in C# Out Put 1.1
Tasks in C# Out Put 1.1

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?