Mutexes in Visual Basic .NET
In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple threads.
Imports System
Imports System.Collections.Generic
Imports System.Threading
Public Class Container
Private ReadOnly _lock As New Object()
Private ReadOnly _counters As New Dictionary(Of String, Integer)
Public Sub New()
_counters("a") = 0
_counters("b") = 0
End Sub
Public Sub Increment(name As String)
SyncLock _lock
_counters(name) += 1
End SyncLock
End Sub
Public Function GetCounters() As Dictionary(Of String, Integer)
Return New Dictionary(Of String, Integer)(_counters)
End Function
End Class
Public Module Program
Public Sub Main()
Dim c As New Container()
Dim doIncrement = Sub(name As String, n As Integer)
For i As Integer = 0 To n - 1
c.Increment(name)
Next
End Sub
Dim tasks As New List(Of Task)()
tasks.Add(Task.Run(Sub() doIncrement("a", 10000)))
tasks.Add(Task.Run(Sub() doIncrement("a", 10000)))
tasks.Add(Task.Run(Sub() doIncrement("b", 10000)))
Task.WaitAll(tasks.ToArray())
Console.WriteLine(String.Join(", ", c.GetCounters().Select(Function(kvp) $"{kvp.Key}: {kvp.Value}")))
End Sub
End Module
The Container
class holds a dictionary of counters. Since we want to update it concurrently from multiple threads, we add a lock object to synchronize access. Note that in VB.NET, we use SyncLock
instead of a Mutex
for simplicity in this example.
The Increment
method locks the object before accessing _counters
, ensuring thread-safe access.
In the Main
method, we create an instance of Container
and define a lambda function doIncrement
that increments a named counter in a loop.
We then create multiple tasks to run doIncrement
concurrently, simulating concurrent access to the same Container
instance.
After waiting for all tasks to complete, we print the final state of the counters.
Running the program shows that the counters are updated as expected:
a: 20000, b: 10000
In this VB.NET version, we’ve used Task
s and the Task.Run
method to create concurrent operations, which is analogous to goroutines in Go. The SyncLock
statement provides mutual exclusion, similar to the Mutex
in the original Go code.
Next, we could look at implementing this same state management task using only asynchronous methods and message passing, which would be more similar to the concept of goroutines and channels in Go.