How to synchronize the access to a shared resource in a multithreading environment with Visual Basic .NET or Visual Basic 2005

This article was previously published under Q316136
This article has been archived. It is offered "as is" and will no longer be updated.
SUMMARY
Visual Basic .NET or Visual Basic 2005 applications can perform multiple tasks simultaneously by using multithreading. Multithreading can start different threads to complete different tasks simultaneously, and multithreading improves the performance and responsiveness of your applications.

Because multiple threads can access a resource at the same time, you may want to synchronize individual threads with other parts of your program. This article describes some common scenarios with multithreading programming and explains how to synchronize the access to a shared resource among the multiple threads.

back to the top

How to Protect Your Global Data in Modules in a Multithreaded Environment

The public fields in modules are accessible to all the threads in your application. To synchronize the access to the public fields, you can use property instead of field, and use a ReaderWriterLock object to control the access. To do this, follow these steps:
  1. Open Visual Studio .NET or Visual Studio 2005.
  2. On the File menu, click New Project.
  3. In the tree view on the left, select Visual Basic, and then select Console Application in the list view on the right. Press ENTER.
  4. Module1 is generated automatically. Delete all the code in Module1, and then paste the following code into Module1:
    Option Explicit On Option Strict OnImports SystemImports System.ThreadingModule Module1    Sub Main()        Dim threadArray(20) As Thread        Dim threadNum As Integer        'Create 20 threads.        For threadNum = 0 To 19            threadArray(threadNum) = New Thread(AddressOf AccessGlobalResource)        Next threadNum        'Start the threads.        For threadNum = 0 To 19            threadArray(threadNum).Start()        Next        'Wait until all of the thread spawn out finish.        For threadNum = 0 To 19            threadArray(threadNum).Join()        Next        Console.WriteLine("All operations have completed. Press enter to exit")        Console.ReadLine()    End Sub    Sub AccessGlobalResource()        Dim rnd As New Random()        Dim theNumber As Long        If rnd.Next Mod 2 <> 0 Then            theNumber = Number        Else            theNumber = rnd.Next            Number = theNumber        End If    End Sub 'AccessGlobalResourceEnd Module					
  5. Right-click the project in Solution Explorer, and then click Add/Add Module. Add Module2.vb to the project.

    Note In Visual Studio 2005, right-click the project in Solution Explorer, and then click Add/Module.
  6. Delete all the code that is generated by default, and then paste the following code into Module2:
    Option Explicit On Option Strict OnImports SystemImports System.ThreadingModule Module2    Private rwl As New ReaderWriterLock()    Private myNumber As Long    Public Property Number() As Long        Get            'Acquire a Read lock on the resource.            rwl.AcquireReaderLock(Timeout.Infinite)            Try                Console.WriteLine("Thread:{0} starts getting the Number", Thread.CurrentThread.GetHashCode)                Thread.Sleep(50)                Number = myNumber                Console.WriteLine("Thread:{0} got the Number", Thread.CurrentThread.GetHashCode)            Finally                'Release the lock.                rwl.ReleaseReaderLock()            End Try        End Get        Set(ByVal Value As Long)            'Acquire a Write lock on the resource.            rwl.AcquireWriterLock(Timeout.Infinite)            Try                Console.WriteLine("Thread: {0} start writing the Number", Thread.CurrentThread.GetHashCode)                Thread.Sleep(50)                myNumber = Value                Console.WriteLine("Thread: {0} written the Number", Thread.CurrentThread.GetHashCode)            Finally                'Release the lock.                rwl.ReleaseWriterLock()            End Try        End Set    End PropertyEnd Module						
  7. Compile the project and then run it.
back to the top

How to Make Your Class Thread-Safe

Multiple threads may try to access an object at the same time. When more than one thread simultaneously competes for access to an object, it is possible that some threads may get an invalid state if another thread modifies the resource at the same time. For example, if a thread is reading the object's field while another thread is modifying the field, the first thread may get an invalid state of the field.This situation is called a race condition.

To avoid this situation, you can protect critical sections of your code from race conditions by employing locks. A lock, represented by the Visual Basic keyword SyncLock Statement, allows a single thread of execution to obtain exclusive execution rights on an object. The following example steps demonstrate locks:
  1. Open Visual Studio .NET.
  2. On the File menu, click New Project.
  3. In the tree view on the left, select Visual Basic, and then select Console Application in the list view on the right. Press ENTER.
  4. Module1 is generated automatically. Delete all the code in Module1, and then paste the following code into Module1:
    Option Explicit On Option Strict OnImports SystemImports System.ThreadingModule Module1    Public WorkItemNum As Integer = 20    Public Done As New AutoResetEvent(False)    Sub Main()        Dim threadNum As Integer        Dim AStudent As New Student()        'Queue up 20 work items in the ThreadPool.        For threadNum = 0 To WorkItemNum - 1            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf AccessClassResource), AStudent)        Next threadNum        Done.WaitOne()        Console.WriteLine("All operations have completed. Press enter to exit")        Console.ReadLine()    End Sub    Sub AccessClassResource(ByVal state As Object)        Dim rnd As New Random()        Dim theName As String        Dim AStudent As Student = CType(state, Student)        If rnd.Next Mod 2 <> 0 Then             'Do some thing with the static member: TeacherName.            If rnd.Next Mod 2 <> 0 Then  'write to the TeacherName.                Select Case rnd.Next Mod 3                    Case 0                        Student.TeacherName = "Tom"                    Case 1                        Student.TeacherName = "Mike"                    Case 2                        Student.TeacherName = "John"                End Select            Else 'read the static member.                theName = Student.TeacherName            End If        Else   'Do something with the instance member.            If rnd.Next Mod 2 <> 0 Then  'write to the instance member.                Select Case rnd.Next Mod 3                    Case 0                        AStudent.SetName("Janet")                    Case 1                        AStudent.SetName("David")                    Case 2                        AStudent.SetName("Ben")                End Select            Else 'read the instance member.                theName = AStudent.GetName()            End If        End If        'Because it is possible that multiple threads may access the WorkItemNum,         'you must use the Interlocked.Decrement to decrease it.        If Interlocked.Decrement(WorkItemNum) = 0 Then            'Set the event to notify the main thread that all work is completed.            Done.Set()        End If    End Sub 'AccessClassResourceEnd Module					
  5. Right-click the project in Solution Explorer, and then click Add/Add Class. Add Class1.vb to the project.

    Note In Visual Studio 2005, right-click the project in Solution Explorer, and then click Add/Class.
  6. Delete all the code that is generated by default, and then paste the following code into Class1.vb:
    Option Explicit On Option Strict OnImports SystemImports System.ThreadingPublic Class Student    Private Shared myTeacherName As String = "Bill"    Private myName As String = "Grace"    Public Shared Property TeacherName() As String        Get            Dim theName As String            SyncLock GetType(Student) 'Synchronize access to the shared member.                Console.WriteLine("Thread {0} starts to get the teacher's name", Thread.CurrentThread.GetHashCode)                theName = myTeacherName                'Wait for 0.3 second.                Thread.Sleep(300)                Console.WriteLine("Thread {0} finished to get the teacher's name:{1}.", Thread.CurrentThread.GetHashCode, theName)            End SyncLock            Return theName        End Get        Set(ByVal Value As String)            SyncLock GetType(Student) 'Synchronize access to the shared member.                Console.WriteLine("Thread {0} starts to set the teacher's name.", Thread.CurrentThread.GetHashCode)                myTeacherName = Value                'Wait for 0.3 second.                Thread.Sleep(300)                Console.WriteLine("Thread {0} finished to set the teacher's name:{1}.", Thread.CurrentThread.GetHashCode, Value)            End SyncLock        End Set    End Property    Public Function GetName() As String        Dim theName As String        SyncLock Me 'Synchronize access to the shared member.            Console.WriteLine("Thread {0} starts to get the student's name.", Thread.CurrentThread.GetHashCode)            theName = myName            'Wait for 0.3 second.            Thread.Sleep(300)            Console.WriteLine("Thread {0} finished to get the student's name:{1}", Thread.CurrentThread.GetHashCode, theName)            Return theName        End SyncLock    End Function    Public Function SetName(ByVal NewName As String) As String        Dim theOldName As String        SyncLock Me 'Synchronize access to the shared member.            Console.WriteLine("Thread {0} starts to set the student's name.", Thread.CurrentThread.GetHashCode)            theOldName = myName            myName = NewName            'Wait for 0.3 second.            Thread.Sleep(300)            Console.WriteLine("Thread {0} finished to set the student's name:{1}", Thread.CurrentThread.GetHashCode, NewName)        End SyncLock        Return theOldName    End FunctionEnd Class					
  7. Compile the project and then run it.
back to the top
REFERENCES
For more information about this subject, see the following Microsoft MSDN Web sites:back to the top
Properties

Article ID: 316136 - Last Review: 02/28/2014 04:31:48 - Revision: 3.3

  • Microsoft Visual Basic 2005
  • Microsoft Visual Basic .NET 2003 Standard Edition
  • Microsoft Visual Basic .NET 2002 Standard Edition
  • kbnosurvey kbarchive kbvs2005swept kbvs2005applies kbhowtomaster KB316136
Feedback