Since VB.NET runs with the Common Language Runtime (CLR), it gains many new capabilities, one of which is the ability to create free-threaded applications.
Working with Threads
VB.NET makes it easy to start working with threads. There are some subtleties that we will explore later, but let's jump in and create a simple form that spawns a new thread to run a background process. The first thing we will need to do is create the background task that will be run on the new thread. The following code executes a rather long running process—an infinite loop:
Private Sub BackgroundProcess()
Dim i As Integer = 1
Do While True
ListBox1.Items.Add("Iterations: " + i)
i += 1
Loop
End Sub
The following code creates a new Thread object and passes it a reference to BackgroundProcess:Dim t As Thread
t = New Thread(AddressOf Me.BackgroundProcess)
t.Start()
The AddressOf operator creates a delegate object to the BackgroundProcess method. A delegate within VB.NET is a type-safe, object-oriented function pointer. After the thread has been instantiated, you begin the execution of the code by calling the Start() method of the thread.Passing Data Through Multithreaded Procedures
The last example shows a rather simple situation. Multithreading has many complications that you have to work out when you program. One issue that you will run into is passing data to and from the procedure passed to the constructor of the Thread class. That is to say, the procedure you want to kick off on another thread cannot be passed any parameters and you cannot return data from that procedure. This is because the procedure you pass to the thread constructor cannot have any parameters or return value. To get around this, wrap your procedure in a class where the parameters to the method are written as fields of the class.
A simple example of this would be if we had a procedure that calculated the square of a number:
Function Square(ByVal Value As Double) As Double
Return Value * Value
End Function
To make this procedure available to be used in a new thread we would wrap it in a class: Public Class SquareClass
Public Value As Double
Public Square As Double
Public Sub CalcSquare()
Square = Value * Value
End Sub
End Class
Use this code to start the CalcSquare procedure on a new thread. following code:Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim oSquare As New SquareClass()
t = New Thread(AddressOf oSquare.CalcSquare)
oSquare.Value = 30
t.Start()
End Sub
Synchronizing the ThreadsVB.NET contains a few statements to provide synchronization of threads. In the Square example, you would want to synchronize the thread performing the calculation in order to wait for the calculation to complete so you can retrieve the result. Another example would be if you sort an array on a different thread and you would wait for that process to complete before using the array. To perform these synchronizations, VB.NET provides the SyncLockEnd SyncLock statement and the Thread.Join method.
SyncLock gains an exclusive lock to an object reference that is passed to it. By gaining this exclusive lock you can ensure that multiple threads are not accessing shared data or that the code is executing on multiple threads. A convenient object to use in order to gain a lock is the System.Type object associated with each class. The System.Type object can be retrieved using the GetType method:
Public Sub CalcSquare()
SyncLock GetType(SquareClass)
Square = Value * Value
End SyncLock
End Sub
....