How to synchronize the access to a shared resource in a multithreading environment with Visual Basic .NET or Visual Basic 2005 (316136)
The information in this article applies to:
- Microsoft Visual Basic 2005
- Microsoft Visual Basic .NET (2003)
- Microsoft Visual Basic .NET (2002)
This article was previously published under Q316136 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:
- Open Visual Studio .NET or Visual Studio 2005.
- On the File menu, click New Project.
- In the tree view on the left, select Visual Basic, and then select Console Application in the list view on the right. Press ENTER.
- Module1 is generated automatically. Delete all the code in Module1, and then paste the following code into Module1:
Option Explicit On
Option Strict On
Imports System
Imports System.Threading
Module 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 'AccessGlobalResource
End Module
- 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. - Delete all the code that is generated by default, and then paste the following code into Module2:
Option Explicit On
Option Strict On
Imports System
Imports System.Threading
Module 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 Property
End Module
- 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:
- Open Visual Studio .NET.
- On the File menu, click New Project.
- In the tree view on the left, select Visual Basic, and then select Console Application in the list view on the right. Press ENTER.
- Module1 is generated automatically. Delete all the code in Module1, and then paste the following code into Module1:
Option Explicit On
Option Strict On
Imports System
Imports System.Threading
Module 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 'AccessClassResource
End Module
- 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. - Delete all the code that is generated by default, and then paste the following code into Class1.vb:
Option Explicit On
Option Strict On
Imports System
Imports System.Threading
Public 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 Function
End Class
- 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
Modification Type: | Minor | Last Reviewed: | 10/3/2006 |
---|
Keywords: | kbvs2005swept kbvs2005applies kbHOWTOmaster KB316136 kbAudDeveloper |
---|
|