Hereβs a detailed hands-on exercise plan for mastering Concurrency and Parallel Programming in C# (2025). Each phase includes concepts, code examples, and exercises to help you solidify your skills.
π Phase 1: Fundamentals of Multithreading in C#
Concepts to Learn:
β Understanding Threads and how the Thread class works
β Managing Thread Lifecycle (Start, Sleep, Join, Abort)
β Thread Synchronization (lock, Monitor, Mutex, Semaphore, AutoResetEvent, ManualResetEvent)
β Avoiding Race Conditions & Deadlocks
Exercise 1: Creating a Simple Thread
π Task: Create a new thread that prints numbers from 1 to 10.
β
Goal: Understand how to create and start a thread.
using System;
using System.Threading;
class Program
{
static void PrintNumbers()
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($"Thread: {i}");
Thread.Sleep(500); // Simulate work
}
}
static void Main()
{
Thread thread = new Thread(PrintNumbers);
thread.Start();
thread.Join(); // Wait for thread to finish
Console.WriteLine("Main Thread Exiting...");
}
}
Exercise 2: Thread Synchronization with lock
π Task: Create two threads that increment a shared counter.
β
Goal: Prevent race conditions using lock.
using System;
using System.Threading;
class Program
{
static int counter = 0;
static object lockObject = new object();
static void Increment()
{
for (int i = 0; i < 1000; i++)
{
lock (lockObject) // Prevent race condition
{
counter++;
}
}
}
static void Main()
{
Thread t1 = new Thread(Increment);
Thread t2 = new Thread(Increment);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine($"Final Counter: {counter}");
}
}
Exercise 3: Avoiding Deadlocks
π Task: Simulate a deadlock and fix it using proper lock ordering.
β
Goal: Learn deadlock prevention strategies.
using System;
using System.Threading;
class Program
{
static object lock1 = new object();
static object lock2 = new object();
static void Thread1()
{
lock (lock1)
{
Thread.Sleep(100);
lock (lock2)
{
Console.WriteLine("Thread1 acquired both locks.");
}
}
}
static void Thread2()
{
lock (lock2)
{
Thread.Sleep(100);
lock (lock1) // Reversed order causes deadlock
{
Console.WriteLine("Thread2 acquired both locks.");
}
}
}
static void Main()
{
Thread t1 = new Thread(Thread1);
Thread t2 = new Thread(Thread2);
t1.Start();
t2.Start();
t1.Join();
t2.Join();
}
}
πΉ Fix: Ensure both threads lock objects in the same order.
π Phase 2: Task-Based Asynchronous Programming (TAP)
Concepts to Learn:
β Understanding Task and Task.Run()
β Using ContinueWith() for task chaining
β Implementing Parallel.ForEach and Parallel.Invoke
Exercise 1: Running Tasks in Parallel
π Task: Run multiple tasks concurrently.
β
Goal: Understand Task.Run().
using System;
using System.Threading.Tasks;
class Program
{
static void TaskMethod()
{
Console.WriteLine($"Task Running on Thread {Task.CurrentId}");
}
static void Main()
{
Task t1 = Task.Run(TaskMethod);
Task t2 = Task.Run(TaskMethod);
Task.WaitAll(t1, t2);
Console.WriteLine("All tasks completed.");
}
}
Exercise 2: Using Parallel.ForEach
π Task: Process a list of numbers using Parallel.ForEach().
β
Goal: Use PLINQ for faster processing.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static void Main()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
Parallel.ForEach(numbers, number =>
{
Console.WriteLine($"Processing {number} on thread {Task.CurrentId}");
});
Console.WriteLine("Processing complete.");
}
}
π Phase 3: Asynchronous Programming with async/await
Concepts to Learn:
β Async/Await Basics
β Task.Delay(), ConfigureAwait(false)
β Handling Exceptions in Async Methods
Exercise 1: Making an Async HTTP Request
π Task: Fetch data from an API asynchronously.
β
Goal: Learn awaiting I/O-bound operations.
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task FetchDataAsync()
{
using HttpClient client = new HttpClient();
string data = await client.GetStringAsync("https://jsonplaceholder.typicode.com/posts/1");
Console.WriteLine(data);
}
static async Task Main()
{
await FetchDataAsync();
}
}
Exercise 2: Async File Read
π Task: Read a file asynchronously.
β
Goal: Learn I/O-bound async operations.
using System;
using System.IO;
using System.Threading.Tasks;
class Program
{
static async Task ReadFileAsync(string path)
{
using StreamReader reader = new StreamReader(path);
string content = await reader.ReadToEndAsync();
Console.WriteLine(content);
}
static async Task Main()
{
await ReadFileAsync("test.txt");
}
}
π Phase 4: Data Parallelism & PLINQ
Exercise: Parallel LINQ (PLINQ)
π Task: Filter large datasets using PLINQ.
β
Goal: Learn parallelized LINQ queries.
using System;
using System.Linq;
class Program
{
static void Main()
{
var numbers = Enumerable.Range(1, 100000);
var evenNumbers = numbers.AsParallel().Where(n => n % 2 == 0).ToList();
Console.WriteLine($"Total even numbers: {evenNumbers.Count}");
}
}
π Phase 5: Advanced Concurrency
Exercise: Producer-Consumer Pattern
π Task: Implement a producer-consumer pattern using BlockingCollection.
β
Goal: Learn thread-safe queue processing.
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static BlockingCollection<int> queue = new BlockingCollection<int>();
static void Producer()
{
for (int i = 0; i < 5; i++)
{
queue.Add(i);
Console.WriteLine($"Produced: {i}");
Thread.Sleep(100);
}
queue.CompleteAdding();
}
static void Consumer()
{
foreach (var item in queue.GetConsumingEnumerable())
{
Console.WriteLine($"Consumed: {item}");
}
}
static void Main()
{
Task.Run(Producer);
Task.Run(Consumer).Wait();
}
}
Final Step: Real-World Projects
β Build a high-performance API
β Optimize concurrent processing in microservices
β Implement parallel image processing
π
Top comments (1)
good topic