Microsoft KB Archive/316136

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

Article ID: 316136

Article Last Modified on 12/6/2006

-

APPLIES TO


 * Microsoft Visual Basic 2005
 * Microsoft Visual Basic .NET 2003 Standard Edition
 * Microsoft Visual Basic .NET 2002 Standard Edition

-



This article was previously published under Q316136



IN THIS TASK
SUMMARY
 * How to Protect Your Global Data in Modules in a Multithreaded Environment
 * How to Make Your Class Thread-Safe

REFERENCES



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(&quot;All operations have completed. Press enter to exit&quot;) 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(&quot;Thread:{0} starts getting the Number&quot;, Thread.CurrentThread.GetHashCode) Thread.Sleep(50) Number = myNumber Console.WriteLine(&quot;Thread:{0} got the Number&quot;, 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(&quot;Thread: {0} start writing the Number&quot;, Thread.CurrentThread.GetHashCode) Thread.Sleep(50) myNumber = Value Console.WriteLine(&quot;Thread: {0} written the Number&quot;, Thread.CurrentThread.GetHashCode) Finally 'Release the lock. rwl.ReleaseWriterLock End Try End Set End Property End Module

 Compile the project and then run it.</li></ol>

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: <ol> Open Visual Studio .NET.</li> On the File menu, click New Project.</li> In the tree view on the left, select Visual Basic, and then select Console Application in the list view on the right. Press ENTER.</li>  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(&quot;All operations have completed. Press enter to exit&quot;) 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 = &quot;Tom&quot; Case 1 Student.TeacherName = &quot;Mike&quot; Case 2 Student.TeacherName = &quot;John&quot; 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(&quot;Janet&quot;) Case 1 AStudent.SetName(&quot;David&quot;) Case 2 AStudent.SetName(&quot;Ben&quot;) 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

</li> 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.</li>  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 = &quot;Bill&quot; Private myName As String = &quot;Grace&quot;

Public Shared Property TeacherName As String Get Dim theName As String

SyncLock GetType(Student) 'Synchronize access to the shared member. Console.WriteLine(&quot;Thread {0} starts to get the teacher's name&quot;, Thread.CurrentThread.GetHashCode) theName = myTeacherName 'Wait for 0.3 second. Thread.Sleep(300) Console.WriteLine(&quot;Thread {0} finished to get the teacher's name:{1}.&quot;, 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(&quot;Thread {0} starts to set the teacher's name.&quot;, Thread.CurrentThread.GetHashCode) myTeacherName = Value 'Wait for 0.3 second. Thread.Sleep(300) Console.WriteLine(&quot;Thread {0} finished to set the teacher's name:{1}.&quot;, 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(&quot;Thread {0} starts to get the student's name.&quot;, Thread.CurrentThread.GetHashCode) theName = myName 'Wait for 0.3 second. Thread.Sleep(300) Console.WriteLine(&quot;Thread {0} finished to get the student's name:{1}&quot;, 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(&quot;Thread {0} starts to set the student's name.&quot;, Thread.CurrentThread.GetHashCode) theOldName = myName myName = NewName 'Wait for 0.3 second. Thread.Sleep(300) Console.WriteLine(&quot;Thread {0} finished to set the student's name:{1}&quot;, Thread.CurrentThread.GetHashCode, NewName) End SyncLock

Return theOldName End Function End Class

</li> Compile the project and then run it.</li></ol>

back to the top

<div class="references_section">