Multithreading and Parallel Programming

31.1 Threads

Imports System.Threading

Dim t As New Thread(Sub()
                        For i = 1 To 5
                            Console.WriteLine($"Worker {Thread.CurrentThread.ManagedThreadId}: {i}")
                            Thread.Sleep(100)
                        Next
                    End Sub)
t.IsBackground = True
t.Start()
t.Join()                              ' wait for it to finish
ThreadPool.QueueUserWorkItem(Sub(state) Console.WriteLine("Pool work"))

31.2 Synchronization

Private ReadOnly _lock As New Object()
Private _counter As Integer

Sub Increment()
    SyncLock _lock                     ' like C#'s lock
        _counter += 1
    End SyncLock
End Sub

Interlocked.Increment(_counter)        ' atomic operation
Dim mutex As New Mutex(False, "Global\MyAppMutex")    ' cross-process (single-instance apps)
Dim sem As New SemaphoreSlim(3)                       ' limit concurrency
Await sem.WaitAsync()
Try
    ' limited section
Finally
    sem.Release()
End Try
' Also: Monitor, ReaderWriterLockSlim, ManualResetEventSlim, CountdownEvent, Barrier

31.3 Task Parallel Library (TPL)

Imports System.Threading.Tasks

Parallel.For(0, 100, Sub(i)
                         ProcessItem(i)
                     End Sub)

Parallel.ForEach(files, New ParallelOptions With {.MaxDegreeOfParallelism = 4},
                 Sub(file) CompressFile(file))

Parallel.Invoke(Sub() TaskA(), Sub() TaskB(), Sub() TaskC())

Dim squares = Enumerable.Range(1, 1_000_000).AsParallel().
                         Where(Function(n) n Mod 3 = 0).
                         Select(Function(n) CLng(n) * n).
                         Sum()                                       ' PLINQ

Await Parallel.ForEachAsync(urls, Async Function(url, token)           ' .NET 6+
                                      Dim html = Await client.GetStringAsync(url, token)
                                  End Function)

31.4 Thread-Safe Collections and Producer/Consumer

Imports System.Collections.Concurrent
Dim cache As New ConcurrentDictionary(Of String, Integer)
cache.AddOrUpdate("key", 1, Function(k, old) old + 1)
Dim value = cache.GetOrAdd("other", Function(k) ExpensiveLookup(k))

Dim queue As New BlockingCollection(Of String)(boundedCapacity:=100)
Dim producer = Task.Run(Sub()
                            For i = 1 To 10
                                queue.Add($"item {i}")
                            Next
                            queue.CompleteAdding()
                        End Sub)
Dim consumer = Task.Run(Sub()
                            For Each item In queue.GetConsumingEnumerable()
                                Console.WriteLine(item)
                            Next
                        End Sub)
Task.WaitAll(producer, consumer)
' Also: System.Threading.Channels for modern async pipelines

31.5 Timers

System.Threading.Timer (thread pool), System.Timers.Timer (event-based), System.Windows.Forms.Timer (UI thread), DispatcherTimer (WPF), and PeriodicTimer (.NET 6+, async).