15 minlesson

Task Basics

Task Basics

The Task class is the foundation of modern async programming in C#. It represents an asynchronous operation that may or may not return a value.

Task vs Thread

ThreadTask
Low-level OS constructHigh-level abstraction
Manual lifecycle managementAutomatic management
No built-in return valueTask<T> returns values
Exception crashes appExceptions are captured
Limited compositionRich composition (WhenAll, etc.)

Creating Tasks

Task.Run()

The most common way to run code on a background thread:

csharp
1// Run work on thread pool
2Task task = Task.Run(() =>
3{
4 Console.WriteLine("Running on background thread");
5});
6
7// Wait for completion
8task.Wait();

Task with Return Value

csharp
1// Task<T> returns a value
2Task<int> task = Task.Run(() =>
3{
4 Thread.Sleep(1000); // Simulate work
5 return 42;
6});
7
8// Get the result (blocks until complete)
9int result = task.Result;
10Console.WriteLine($"Result: {result}");

Task.Factory.StartNew()

For advanced scenarios with more options:

csharp
1Task task = Task.Factory.StartNew(
2 () => DoWork(),
3 CancellationToken.None,
4 TaskCreationOptions.LongRunning, // Use dedicated thread
5 TaskScheduler.Default
6);

Task States

A task progresses through several states:

csharp
1Task task = Task.Run(() => Thread.Sleep(1000));
2
3Console.WriteLine(task.Status); // WaitingToRun or Running
4task.Wait();
5Console.WriteLine(task.Status); // RanToCompletion

Possible states:

  • Created - Task created but not started
  • WaitingForActivation - Awaiting scheduling
  • WaitingToRun - Scheduled, waiting for thread
  • Running - Currently executing
  • RanToCompletion - Completed successfully
  • Faulted - Threw an exception
  • Canceled - Was canceled

Checking Task Status

csharp
1Task<int> task = Task.Run(() => ComputeValue());
2
3// Check various properties
4bool isComplete = task.IsCompleted; // Finished (any reason)
5bool isSuccess = task.IsCompletedSuccessfully; // No errors
6bool isFaulted = task.IsFaulted; // Threw exception
7bool isCanceled = task.IsCanceled; // Was canceled
8
9// Get exception if faulted
10if (task.IsFaulted)
11{
12 AggregateException ex = task.Exception;
13}

Waiting for Tasks

Wait()

Blocks the current thread:

csharp
1Task task = Task.Run(() => DoWork());
2task.Wait(); // Blocks until complete
3
4// With timeout
5bool completed = task.Wait(5000); // Wait max 5 seconds

Result Property

Blocks and returns the value:

csharp
1Task<string> task = Task.Run(() => FetchData());
2string data = task.Result; // Blocks until complete

Warning: Using Wait() or Result can cause deadlocks in UI/ASP.NET contexts. Prefer await.

Completed Tasks

For returning already-completed tasks:

csharp
1// Already completed with value
2Task<int> completed = Task.FromResult(42);
3
4// Already completed (no value)
5Task done = Task.CompletedTask;
6
7// Already failed
8Task failed = Task.FromException(new InvalidOperationException());
9
10// Already canceled
11Task canceled = Task.FromCanceled(new CancellationToken(true));

Task vs Task

csharp
1// Task - no return value (like void)
2Task task1 = Task.Run(() =>
3{
4 Console.WriteLine("No return value");
5});
6
7// Task<T> - returns a value
8Task<int> task2 = Task.Run(() =>
9{
10 return 42; // Returns int
11});
12
13int value = await task2; // Get the value

Complete Example

csharp
1Console.WriteLine("Starting tasks...");
2
3// Create multiple tasks
4Task<int> task1 = Task.Run(() =>
5{
6 Thread.Sleep(1000);
7 return 10;
8});
9
10Task<int> task2 = Task.Run(() =>
11{
12 Thread.Sleep(500);
13 return 20;
14});
15
16Task<int> task3 = Task.Run(() =>
17{
18 Thread.Sleep(1500);
19 return 30;
20});
21
22// Wait for all and get results
23Task.WaitAll(task1, task2, task3);
24
25int total = task1.Result + task2.Result + task3.Result;
26Console.WriteLine($"Total: {total}"); // 60

Key Takeaways

  • Task represents an async operation
  • Task<T> returns a value of type T
  • Task.Run() executes code on the thread pool
  • Task.Wait() and .Result block (avoid in async contexts)
  • Tasks capture exceptions instead of crashing
  • Use Task.FromResult() for pre-completed tasks