Synchronization in Multi-threaded Applications in VB.NET

Description

The Attached code demonstrates important concept in multithreading, which is Synchronization.

I am calling a group of two text boxes and a label as a two counter as in (FirstTwoCounter, SecondTwoCounter, ThirdTwoCounter, etc.). I have five such twocounters.

Textboxes in FirstTwoCounter are incremented by thread FirstTwoCounterThread (it actually calls IncrementFirstTwoCounter function). Similarly textboxes in SecondTwoCounter are incremented by thread SecondTwoCounterThread (it actually calls IncrementSecondTwoCounter function) and so on.

I have a thread called WatchThread, apparently it looks like it does a needless job, which watches each of the twocounters and sees if their count is out of sync.This thread increments a static variable NoOfUnsyncs which keeps track of count of total unsyncs in any of the two counters and displays in a text box.

If you run this code surprisingly you would see that there are some unsyncs. Reason being,when there are multiple threads you never know when a thread is stopped and at what point of line of execution.For example it would happen that execution is stopped in IncrementFirstTwoCounter function after execution of the line txtFirstTwoCounter1.Text = Int32.ToString(FirstTwoCounterCnt1 ++) and watcher thread would have been called. At this point watcher thread would see that. FirstTwoCounterCnt1++ and FirstTwoCounterCnt2++ are out of sync . Preventing this kind of collision is simply a matter of putting a lock on a resource when one thread is using it. The first thread that accesses a resource locks it, and then the other threads cannot access that resource until it is unlocked To achieve this compile the code by using Monitor.Enter(this) and Monitor.Exit(this) between critical section.Now when you run the app and click on start button you would see that NofUnsyncs remains 0. I have already put this code in all five incremental function and watchcounter function.you just need to uncomment this and compile and run.

NOTE:

If you don't see unsync being incremented initially wait for sometime or try maximizing the form and then minimizing it.

What is needed to compile?

.NET SDK

How to Compile?

vbc /r:System.dll /r:System.winforms.dll /r:System.drawing.dll/r:Microsoft.win32.interop.dll Sync_thread2.vb

Code:

Imports System
Imports System.Drawing
'using System.Collections;
Imports System.ComponentModel
Imports System.WinForms
'using System.Data;
Imports System.Threading
Namespace synchronization
' <summary>
Public Class Form1
Inherits System.WinForms.Form
' <summary>
' Required designer variable.
' </summary>
Private components As System.ComponentModel.Container
Private WithEvents cmdExit As System.WinForms.Button
Private label11 As System.WinForms.Label
Private label8 As System.WinForms.Label
Private txtFifthTwoCounter2 As System.WinForms.TextBox
Private txtFifthTwoCounter1 As System.WinForms.TextBox
Private label4 As System.WinForms.Label
Private label10 As System.WinForms.Label
Private label9 As System.WinForms.Label
Private txtFourthTwoCounter2 As System.WinForms.TextBox
Private txtFourthTwoCounter1 As System.WinForms.TextBox
Private txtThirdTwoCounter2 As System.WinForms.TextBox
Private WithEvents label7 As System.WinForms.Label
Private txtNoOfUnsync As System.WinForms.TextBox
Private WithEvents cmdStart As System.WinForms.Button
Private label6 As System.WinForms.Label
Private label5 As System.WinForms.Label
Private txtThirdTwoCounter1 As System.WinForms.TextBox
Private label3 As System.WinForms.Label
Private txtSecondTwoCounter2 As System.WinForms.TextBox
Private txtSecondTwoCounter1 As System.WinForms.TextBox
Private label2 As System.WinForms.Label
Private txtFirstTwoCounter2 As System.WinForms.TextBox
Private txtFirstTwoCounter1 As System.WinForms.TextBox
Private label1 As System.WinForms.Label
'Counter variables for FirstTwoCounter
'will be incremented by FirstTwoCounter Thread
Private FirstTwoCounterCnt1 As System.Int32 = 0
Private FirstTwoCounterCnt2 As System.Int32 = 0
'Counter variables for SecondTwoCounter
'will be incremented by SecondTwoCounter Thread
Private SecondTwoCounterCnt1 As System.Int32 = 0
Private SecondTwoCounterCnt2 As System.Int32 = 0
'Counter variables for ThirdTwoCounter
'will be incremented by ThirdTwoCounter Thread
Private ThirdTwoCounterCnt1 As System.Int32 = 0
Private ThirdTwoCounterCnt2 As System.Int32 = 0
'Counter variables for FourthTwoCounter
'will be incremented by FourthTwoCounter Thread
Private FourthTwoCounterCnt1 As System.Int32 = 0
Private FourthTwoCounterCnt2 As System.Int32 = 0
'Counter variables for FifthTwoCounter
'will be incremented by FifthTwoCounter Thread
Private FifthTwoCounterCnt1 As System.Int32 = 0
Private FifthTwoCounterCnt2 As System.Int32 = 0
'Thread For FirstTwoCounter
Private FirstTwoCounterThread As System.Threading.Thread
'Thread For SecondTwoCounter
Private SecondTwoCounterThread As System.Threading.Thread
'Thread For ThirdTwoCounter
Private ThirdTwoCounterThread As System.Threading.Thread
'Thread For FourthTwoCounter
Private FourthTwoCounterThread As System.Threading.Thread
'Thread For FifthTwoCounter
Private FifthTwoCounterThread As System.Threading.Thread
'Watches the counters on all the threads and displays whethere the pairs of counters are equal or out of sync
Private WatchThread As System.Threading.Thread
Private Shared NoOfUnsync As System.Int32 = 0
Public Sub New()
'
' Required for Windows Form Designer support
'
InitializeComponent()
'
' TODO: Add any constructor code after InitializeComponent call
'
txtNoOfUnsync.Text = Int32.ToString(NoOfUnsync)
FirstTwoCounterThread = 
New Thread(New ThreadStart
IncrementFirstTwoCounter))
SecondTwoCounterThread = 
New Thread(New ThreadStart(IncrementSecondTwoCounter))
ThirdTwoCounterThread = 
New Thread(New ThreadStart(IncrementThirdTwoCounter))
FourthTwoCounterThread = 
New Thread(New ThreadStart(IncrementFourthTwoCounter))

FifthTwoCounterThread = New Thread(New ThreadStart(IncrementFifthTwoCounter))
WatchThread = 
New Thread(New ThreadStart(WatchCounters))
End Sub 'New
' <summary>
' Clean up any resources being used.
' </summary>
Public Overrides Sub Dispose()
MyBase.Dispose()
components.Dispose()
'Clean all the threads
If FirstTwoCounterThread.IsAlive Then
FirstTwoCounterThread.Abort()
End If
If
 SecondTwoCounterThread.IsAlive Then
SecondTwoCounterThread.Abort()
End If
If
 ThirdTwoCounterThread.IsAlive Then
ThirdTwoCounterThread.Abort()
End If
If
 FourthTwoCounterThread.IsAlive Then
FourthTwoCounterThread.Abort()
End If
If
 FifthTwoCounterThread.IsAlive Then
FifthTwoCounterThread.Abort()
End If
If
 WatchThread.IsAlive Then
WatchThread.Abort()
End If
FirstTwoCounterThread = Nothing
SecondTwoCounterThread = Nothing
ThirdTwoCounterThread = Nothing
FourthTwoCounterThread = Nothing
FifthTwoCounterThread = Nothing
WatchThread = Nothing
End
 Sub 'Dispose 
' <summary>
' Required method for Designer support - do not modify.
' the contents of this method with the code editor.
' </summary>
Private Sub IncrementFirstTwoCounter()
While True
Thread.Sleep(50)
'Begin of Critical Section.
'Uncomment the following line for proper Synchronization.
'Monitor.Enter(this);
txtFirstTwoCounter1.Text = Int32.ToString(FirstTwoCounterCnt1 ++) 'ToDo: ++ operator not supported within expressions.
txtFirstTwoCounter2.Text = Int32.ToString(FirstTwoCounterCnt2 ++) 'ToDo: ++ operator not supported within expressions.
End While 'Uncomment the following line for proper Synchronization.
End Sub 'IncrementFirstTwoCounter.
'Monitor.Exit(this);
'End Of Critical Section.
Private Sub IncrementSecondTwoCounter()
While True
Thread.Sleep(50)
'Begin Of Critical Section.
'Uncomment the following line for proper Synchronization.
'Monitor.Enter(this);
txtSecondTwoCounter1.Text = Int32.ToString(SecondTwoCounterCnt1 ++) 'ToDo: ++ operator not supported within expressions
txtSecondTwoCounter2.Text = Int32.ToString(SecondTwoCounterCnt2 ++) 'ToDo: ++ operator not supported within expressions.
End While 'Monitor.Exit(this);
End Sub 'IncrementSecondTwoCounter.
'Uncomment the following line for proper Synchronization.
'End Of Critical Section.
Private Sub IncrementThirdTwoCounter()
While True
Thread.Sleep(50)
'Begin Of Critical Section.
'Uncomment the following line for proper Synchronization.
'Monitor.Enter(this);
txtThirdTwoCounter1.Text = Int32.ToString(ThirdTwoCounterCnt1 ++) 'ToDo: ++ operator not supported within expressions.
txtThirdTwoCounter2.Text = Int32.ToString(ThirdTwoCounterCnt2 ++) 'ToDo: ++ operator not supported within expressions.
End While 'Monitor.Exit(this);
End Sub 'IncrementThirdTwoCounter.
'Uncomment the following line for proper Synchronization.
'End Of Critical Section.
Private Sub IncrementFourthTwoCounter()
While True
Thread.Sleep(50)
'Begin Of Critical Section.
'Uncomment the following line for proper Synchronization.
'Monitor.Enter(this);
txtFourthTwoCounter1.Text = Int32.ToString(FourthTwoCounterCnt1 ++) 'ToDo: ++ operator not supported within expressions.
txtFourthTwoCounter2.Text = Int32.ToString(FourthTwoCounterCnt2 ++) 'ToDo: ++ operator not supported within expressions.
End While 'Uncomment the following line for proper Synchronization.
End Sub 'IncrementFourthTwoCounter.
'Monitor.Exit(this);
'End Of Critical Section.
Private Sub IncrementFifthTwoCounter()
While True
Thread.Sleep(50)
'Begin Of Critical Section.
'Uncomment the following line for proper Synchronization.
'Monitor.Enter(this);
txtFifthTwoCounter1.Text = Int32.ToString(FifthTwoCounterCnt1 ++) 'ToDo: ++ operator not supported within expressions.
txtFifthTwoCounter2.Text = Int32.ToString(FifthTwoCounterCnt2 ++) 'ToDo: ++ operator not supported within expressions.
End While 'Uncomment the following line for proper Synchronization.
End Sub 'IncrementFifthTwoCounter.
'Monitor.Exit(this);
'End Of Critical Section.
Private Sub WatchCounters()
While True
Thread.Sleep(50)
'Begin Of Critical Section.
'Uncomment the following line for proper Synchronization.
'Monitor.Enter(this);
If FirstTwoCounterCnt1 <> FirstTwoCounterCnt2 Then
label2.Text = "OutOfSync"
txtNoOfUnsync.Text = Int32.ToString(NoOfUnsync ++) 
'ToDo: ++ operator not supported within expressions.
End If 
If SecondTwoCounterCnt1 <> SecondTwoCounterCnt2 Then
label3.Text = "OutOfSync"
txtNoOfUnsync.Text = Int32.ToString(NoOfUnsync ++) 
'ToDo: ++ operator not supported within expressions.
End If
If
 ThirdTwoCounterCnt1 <> ThirdTwoCounterCnt2 Then
label5.Text = "OutOfSync"
txtNoOfUnsync.Text = Int32.ToString(NoOfUnsync ++) 
'ToDo: ++ operator not supported within expressions.
End If
If
 FourthTwoCounterCnt1 <> FourthTwoCounterCnt2 Then
label8.Text = "OutOfSync"
txtNoOfUnsync.Text = Int32.ToString(NoOfUnsync ++) 
'ToDo: ++ operator not supported within expressions.
End If
If
 FifthTwoCounterCnt1 <> FifthTwoCounterCnt2 Then
label9.Text = "OutOfSync"
txtNoOfUnsync.Text = Int32.ToString(NoOfUnsync ++) 
'ToDo: ++ operator not supported within expressions
End If
End
 While 
End Sub 'WatchCounters.
'Uncomment the following line for proper Synchronization.
'Monitor.Exit(this);
'End Of Critical Section.
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container()
Me
.txtSecondTwoCounter1 = New System.WinForms.TextBox()
Me.cmdExit = New System.WinForms.Button()
Me.cmdStart = New System.WinForms.Button()
Me.label10 = New System.WinForms.Label()
Me.txtSecondTwoCounter2 = New System.WinForms.TextBox()
Me.label2 = New System.WinForms.Label()
Me.label11 = New System.WinForms.Label()
Me.txtFourthTwoCounter1 = New System.WinForms.TextBox()
Me.txtNoOfUnsync = New System.WinForms.TextBox()
Me.txtFirstTwoCounter1 = New System.WinForms.TextBox()
Me.txtFirstTwoCounter2 = New System.WinForms.TextBox()
Me.label4 = New System.WinForms.Label()
Me.txtFifthTwoCounter2 = New System.WinForms.TextBox()
Me
.txtFifthTwoCounter1 = New System.WinForms.TextBox()
Me.label7 = New System.WinForms.Label()
Me.txtFourthTwoCounter2 = New System.WinForms.TextBox()
Me.label8 = New System.WinForms.Label()
Me.label9 = New System.WinForms.Label()
Me.label1 = New System.WinForms.Label()
Me.txtThirdTwoCounter2 = New System.WinForms.TextBox()
Me.label3 = New System.WinForms.Label()
Me.label5 = New System.WinForms.Label()
Me.label6 = New System.WinForms.Label()
Me.txtThirdTwoCounter1 = New System.WinForms.TextBox()
'@design Me.TrayHeight = 0.
'@design Me.TrayLargeIcon = False.
'@design Me.TrayAutoArrange = True.
txtSecondTwoCounter1.Location = New System.Drawing.Point(16, 106)
txtSecondTwoCounter1.TabIndex = 4
txtSecondTwoCounter1.Size = 
New System.Drawing.Size(120, 20)
cmdExit.Location = 
New System.Drawing.Point(400, 224)
cmdExit.Size = 
New System.Drawing.Size(64, 32)
cmdExit.TabIndex = 28
cmdExit.Text = "Exit"
cmdStart.Location = 
New System.Drawing.Point(320, 224)
cmdStart.Size = 
New System.Drawing.Size(72, 32)
cmdStart.TabIndex = 12
cmdStart.Text = "Start"
label10.Location = 
New System.Drawing.Point(16, 232)
label10.Text = "FourthTwoCounter"
label10.Size = 
New System.Drawing.Size(112, 12)
label10.TabIndex = 22
txtSecondTwoCounter2.Location = 
New System.Drawing.Point(16, 130)
txtSecondTwoCounter2.TabIndex = 5
txtSecondTwoCounter2.Size = 
New System.Drawing.Size(120, 20)
label2.Location = 
New System.Drawing.Point(152, 48)
label2.Text = "Counter1=Counter2"
label2.Size = 
New System.Drawing.Size(112, 16)
label2.TabIndex = 3
label11.Location = 
New System.Drawing.Point(16, 320)
label11.Text = "FifthTwoCounter"
label11.Size = 
New System.Drawing.Size(112, 12)
label11.TabIndex = 27
txtFourthTwoCounter1.Location = 
New System.Drawing.Point(16, 256)
txtFourthTwoCounter1.TabIndex = 19
txtFourthTwoCounter1.Size = 
New System.Drawing.Size(120, 20)
txtNoOfUnsync.Location = 
New System.Drawing.Point(320, 176)
txtNoOfUnsync.TabIndex = 13
txtNoOfUnsync.Size = 
New System.Drawing.Size(112, 20)
txtFirstTwoCounter1.Location = 
New System.Drawing.Point(16, 32)
txtFirstTwoCounter1.TabIndex = 1
txtFirstTwoCounter1.Size = 
New System.Drawing.Size(120, 20)
txtFirstTwoCounter2.Location = 
New System.Drawing.Point(16, 56)
txtFirstTwoCounter2.TabIndex = 2
txtFirstTwoCounter2.Size = 
New System.Drawing.Size(120, 20)
label4.Location = 
New System.Drawing.Point(16, 88)
label4.Text = "SeconTwoCounter"
label4.Size = 
New System.Drawing.Size(120, 16)
label4.TabIndex = 23
txtFifthTwoCounter2.Location = 
New System.Drawing.Point(16, 360)
txtFifthTwoCounter2.TabIndex = 25
txtFifthTwoCounter2.Size = 
New System.Drawing.Size(120, 20)
txtFifthTwoCounter1.Location = 
New System.Drawing.Point(16, 336)
txtFifthTwoCounter1.TabIndex = 24
txtFifthTwoCounter1.Size = 
New System.Drawing.Size(120, 20)
label7.Location = 
New System.Drawing.Point(312, 144)
label7.Text = "No of times Unsync occured in any of the two counters"
label7.Size = 
New System.Drawing.Size(160, 24)
label7.TabIndex = 14
txtFourthTwoCounter2.Location = 
New System.Drawing.Point(16, 280)
txtFourthTwoCounter2.TabIndex = 20
txtFourthTwoCounter2.Size = 
New System.Drawing.Size(120, 20)
label8.Location = 
New System.Drawing.Point(152, 272)
label8.Text = "Counter1=Counter2"
label8.Size = 
New System.Drawing.Size(112, 16)
label8.TabIndex = 26
label9.Location = 
New System.Drawing.Point(152, 352)
label9.Text = "Counter1=Counter2"
label9.Size = 
New System.Drawing.Size(112, 16)
label9.TabIndex = 21
label1.Location = 
New System.Drawing.Point(16, 8)
label1.Text = "FirstTwoCounter"
label1.Size = 
New System.Drawing.Size(112, 24)
label1.TabIndex = 0
txtThirdTwoCounter2.Location = 
New System.Drawing.Point(16, 204)
txtThirdTwoCounter2.TabIndex = 18
txtThirdTwoCounter2.Size = 
New System.Drawing.Size(120, 20)
label3.Location = 
New System.Drawing.Point(152, 122)
label3.Text = "Counter1=Counter2"
label3.Size = 
New System.Drawing.Size(112, 16)
label3.TabIndex = 6
label5.Location = 
New System.Drawing.Point(152, 196)
label5.Text = "Counter1=Counter2"
label5.Size = 
New System.Drawing.Size(112, 16)
label5.TabIndex = 10
label6.Location = 
New System.Drawing.Point(24, 164)
label6.Text = "ThirdTwoCounter"
label6.Size = 
New System.Drawing.Size(112, 12)
label6.TabIndex = 11
txtThirdTwoCounter1.Location = 
New System.Drawing.Point(16, 180)
txtThirdTwoCounter1.TabIndex = 8
txtThirdTwoCounter1.Size = 
New System.Drawing.Size(120, 20)
Me.Text = "Importance Of Synchronization"
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(480, 397)
Me.Controls.Add(cmdExit)
Me.Controls.Add(label11)
Me.Controls.Add(label8)
Me.Controls.Add(txtFifthTwoCounter2)
Me.Controls.Add(txtFifthTwoCounter1)
Me.Controls.Add(label4)
Me.Controls.Add(label10)
Me.Controls.Add(label9)
Me.Controls.Add(txtFourthTwoCounter2)
Me.Controls.Add(txtFourthTwoCounter1)
Me.Controls.Add(label7)
Me.Controls.Add(txtNoOfUnsync)
Me.Controls.Add(cmdStart)
Me.Controls.Add(label6)
Me.Controls.Add(label5)
Me.Controls.Add(txtThirdTwoCounter2)
Me.Controls.Add(txtThirdTwoCounter1)
Me.Controls.Add(label3)
Me.Controls.Add(txtSecondTwoCounter2)
Me.Controls.Add(txtSecondTwoCounter1)
Me.Controls.Add(label2)
Me.Controls.Add(txtFirstTwoCounter2)
Me.Controls.Add(txtFirstTwoCounter1)
Me.Controls.Add(label1)
End Sub 'InitializeComponent.
Protected Sub cmdExit_Click(sender As Object, e As System.EventArgs) Handles cmdExit.Click
Close()
End Sub 'cmdExit_Click.
Protected Sub Form1_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs)Handles MyBase.Form1_Closing
End Sub 'Form1_Closing.
Protected Sub label7_Click(sender As Object, e As System.EventArgs) Handles label7.Click
End Sub 'label7_Click.
Protected Sub cmdStart_Click(sender As Object, e As System.EventArgs) Handles cmdStart.Click
FirstTwoCounterThread.Start().
SecondTwoCounterThread.Start().
ThirdTwoCounterThread.Start().
FourthTwoCounterThread.Start().
FifthTwoCounterThread.Start().
WatchThread.Start().
End Sub 'cmdStart_Click.
Protected Sub Form1_Click(sender As Object, e As System.EventArgs) Handles MyBase.Form1_Click
End Sub 'Form1_Click.
'Entry point which delegates to C-style main Private Function.
Public Overloads Shared Sub Main()
Main(System.Environment.GetCommandLineArgs())
End Sub
' <summary>
' The main entry point for the application.
' </summary>
Overloads Public Shared Sub Main(args() As String)
Application.Run(
New Form1())
End Sub 'Main.
End Class 'Form1.
End Namespace 'synchronization.


Similar Articles