🏠 VisualStudioTutor.com  ·  C# Tutorial Home  ·  C# Lesson 27 of 40
Lesson 27 of 40 Async Advanced ⏱ 35 min

Concurrency — Threads, Mutex & Semaphore

Coordinate work that can run at the same time using Thread, SemaphoreSlim, Interlocked, and Mutex while protecting shared resources.

Part 1: What You Will Learn

Coordinate work that can run at the same time using Thread, SemaphoreSlim, Interlocked, and Mutex while protecting shared resources.

  • Start low-level worker threads.
  • Limit concurrent access with `SemaphoreSlim`.
  • Update a shared counter atomically with `Interlocked`.
  • Understand that a named `Mutex` can coordinate access across processes on the same machine.

Project setup: Create a .NET 10 Console App. This is intentionally a low-level concurrency lesson; for most application work, prefer Task and async/await unless you specifically need thread primitives.

Part 2: Topic-Specific Working Example

The following example is written specifically for this lesson. Create the project described above, enter the code, run it, and then change some values to observe how the feature behaves.

using System.Threading;

SemaphoreSlim gate = new(initialCount: 2);
int completed = 0;

void Worker(object? state)
{
    int id = (int)state!;

    gate.Wait();
    try
    {
        Console.WriteLine($"Worker {id} entered.");
        Thread.Sleep(500); // Simulate work

        int total = Interlocked.Increment(ref completed);
        Console.WriteLine($"Worker {id} finished. Total: {total}");
    }
    finally
    {
        gate.Release();
    }
}

Thread[] threads = Enumerable.Range(1, 5)
    .Select(id => new Thread(Worker))
    .ToArray();

for (int i = 0; i < threads.Length; i++)
    threads[i].Start(i + 1);

foreach (Thread thread in threads)
    thread.Join();

// A named Mutex can protect a cross-process resource.
using Mutex mutex = new(false, "Local\\CSharpLesson27Demo");

if (mutex.WaitOne(TimeSpan.FromSeconds(1)))
{
    try
    {
        Console.WriteLine("Exclusive resource acquired.");
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}

Part 3: How the Code Works

  • Five OS threads are created, but the semaphore permits only two workers inside the protected region at a time.
  • `Interlocked.Increment` updates the shared counter atomically without a separate lock.
  • `Join()` blocks the main thread until each worker has completed.
  • A `Mutex` is heavier than a normal lock but can be named and used for cross-process synchronization.

Part 4: Mini Project & Practice

Mini project: simulate six file-processing workers but permit only three concurrent workers. Count completed files with Interlocked and display the final count.

Tip: Type the code yourself in Visual Studio 2026, run it, then deliberately change one part at a time. The goal is to understand the feature rather than simply copy the finished example.

When you are comfortable with this lesson, continue to Lesson 28.

C# in Visual Studio 2026

📘 This lesson is part of the book C# in Visual Studio 2026 by Dr. Liew Voon Kiong.

View on Amazon Kindle Edition