Waitgroups in Visual Basic .NET

Our first example demonstrates the use of a WaitGroup to synchronize multiple threads. Here’s the full source code:

Imports System
Imports System.Threading
Imports System.Threading.Tasks

Module WaitGroupExample
    ' This is the function we'll run in every thread.
    Sub Worker(id As Integer)
        Console.WriteLine($"Worker {id} starting")

        ' Sleep to simulate an expensive task.
        Thread.Sleep(1000)
        Console.WriteLine($"Worker {id} done")
    End Sub

    Sub Main()
        ' This CountdownEvent is used to wait for all the
        ' threads launched here to finish. 
        Dim wg As New CountdownEvent(5)

        ' Launch several threads and increment the CountdownEvent
        ' counter for each.
        For i As Integer = 1 To 5
            ' Wrap the worker call in a Task that makes sure to tell
            ' the CountdownEvent that this worker is done. This way the worker
            ' itself does not have to be aware of the concurrency primitives
            ' involved in its execution.
            Task.Run(Sub()
                         Try
                             Worker(i)
                         Finally
                             wg.Signal()
                         End Try
                     End Sub)
        Next

        ' Block until the CountdownEvent counter goes back to 0;
        ' all the workers notified they're done.
        wg.Wait()

        ' Note that this approach has no straightforward way
        ' to propagate errors from workers. For more
        ' advanced use cases, consider using the
        ' Task.WhenAll method with error handling.
    End Sub
End Module

To run the program, save it as WaitGroupExample.vb and use the Visual Basic compiler:

$ vbc WaitGroupExample.vb
$ mono WaitGroupExample.exe
Worker 3 starting
Worker 1 starting
Worker 2 starting
Worker 5 starting
Worker 4 starting
Worker 3 done
Worker 1 done
Worker 2 done
Worker 5 done
Worker 4 done

The order of workers starting up and finishing is likely to be different for each invocation.

In this Visual Basic .NET example, we use a CountdownEvent as an equivalent to Go’s WaitGroup. The CountdownEvent is initialized with the number of operations we want to wait for, and each operation signals the event when it’s done.

We use Task.Run to start each worker in a separate thread, which is similar to launching goroutines in Go. The Try/Finally block ensures that the CountdownEvent is signaled even if an exception occurs in the worker.

The wg.Wait() call blocks until all workers have finished, just like in the Go example.

Note that Visual Basic .NET and the .NET Framework provide more advanced concurrency patterns, such as the Task Parallel Library, which might be more suitable for complex scenarios.