Microsoft Developer Network

Comprehensive Documentation for .NET Developers

Advanced .NET Concurrency

Dive deep into the intricacies of concurrent programming in .NET. Understand how to leverage multi-threading, asynchronous operations, and synchronization primitives to build responsive, scalable, and efficient applications.

Key Concepts and Topics

Getting Started with Task Parallel Library (TPL)

The Task Parallel Library provides a high-level abstraction for executing tasks in parallel. Here's a basic example:


using System;
using System.Threading.Tasks;

public class TplExample
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Starting parallel processing...");

        Parallel.For(0, 10, i =>
        {
            Console.WriteLine($"Processing item {i} on thread {Task.CurrentId}");
            Thread.Sleep(100); // Simulate work
        });

        Console.WriteLine("Parallel processing complete.");
    }
}
            

Asynchronous Operations with async/await

The async and await keywords simplify writing asynchronous code, making it look almost synchronous. This is crucial for I/O-bound operations like network requests or file access.


using System;
using System.Net.Http;
using System.Threading.Tasks;

public class AsyncExample
{
    public static async Task Main(string[] args)
    {
        Console.WriteLine("Starting asynchronous download...");
        string url = "https://www.example.com"; // Replace with a real URL
        string content = await DownloadContentAsync(url);
        Console.WriteLine($"Downloaded {content.Length} characters.");
    }

    public static async Task<string> DownloadContentAsync(string url)
    {
        using (HttpClient client = new HttpClient())
        {
            return await client.GetStringAsync(url);
        }
    }
}
            

Synchronization Primitives in Action

Protecting shared resources from concurrent access is vital. The lock statement is a common way to achieve this:


using System;
using System.Threading;

public class SynchronizationExample
{
    private static int _counter = 0;
    private static readonly object _lock = new object();

    public static void IncrementCounter()
    {
        lock (_lock) // Ensures only one thread can execute this block at a time
        {
            _counter++;
            Console.WriteLine($"Counter: {_counter} on thread {Thread.CurrentThread.ManagedThreadId}");
        }
    }

    public static void Main(string[] args)
    {
        Thread[] threads = new Thread[5];
        for (int i = 0; i < threads.Length; i++)
        {
            threads[i] = new Thread(IncrementCounter);
            threads[i].Start();
        }

        foreach (Thread t in threads)
        {
            t.Join();
        }

        Console.WriteLine($"Final counter value: {_counter}");
    }
}
            

Understanding the trade-offs between different concurrency models and synchronization mechanisms is key to building robust and performant applications.