Channel Synchronization in C#

This example demonstrates how to use tasks for synchronization in C#. We’ll create a method that simulates work and use a TaskCompletionSource to signal when the work is done.

using System;
using System.Threading.Tasks;

class Program
{
    // This is the method we'll run in a task. The TaskCompletionSource
    // will be used to notify that this method's work is done.
    static async Task Worker(TaskCompletionSource<bool> tcs)
    {
        Console.Write("working...");
        await Task.Delay(1000);  // Simulate work
        Console.WriteLine("done");

        // Signal that we're done
        tcs.SetResult(true);
    }

    static async Task Main()
    {
        // Create a TaskCompletionSource to notify when the work is done
        var tcs = new TaskCompletionSource<bool>();

        // Start a worker task, giving it the TaskCompletionSource
        _ = Worker(tcs);

        // Wait until we receive a notification from the worker
        await tcs.Task;
    }
}

To run the program, compile and execute it:

$ dotnet run
working...done

If you removed the await tcs.Task; line from this program, the program would exit before the Worker even started.

In this C# version:

  1. We use a Task instead of a goroutine to represent concurrent work.
  2. Instead of a channel, we use a TaskCompletionSource<bool> to signal completion.
  3. The Worker method is marked as async and uses await Task.Delay(1000) to simulate work.
  4. In the Main method, we start the worker task and then wait for it to complete using await tcs.Task.

This approach achieves similar synchronization to the original example, ensuring that the main program doesn’t exit until the worker task is complete.