Synchronization in Multi-threading

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 actaully 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?

csc /r:System.dll /r:System.winforms.dll /r:System.drawing.dll
/r:Microsoft.win32.interop.dll Sync_thread2.cs

Source Code

namespace synchronization
{
using System;
using System.Drawing;
//using System.Collections;
using System.ComponentModel;
using System.WinForms;
//using System.Data;
using System.Threading;
/// <summary>
public class Form1 : System.WinForms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components;
private System.WinForms.Button cmdExit;
private System.WinForms.Label label11;
private System.WinForms.Label label8;
private System.WinForms.TextBox txtFifthTwoCounter2;
private System.WinForms.TextBox txtFifthTwoCounter1;
private System.WinForms.Label label4;
private System.WinForms.Label label10;
private System.WinForms.Label label9;
private System.WinForms.TextBox txtFourthTwoCounter2;
private System.WinForms.TextBox txtFourthTwoCounter1;
private System.WinForms.TextBox txtThirdTwoCounter2;
private System.WinForms.Label label7;
private System.WinForms.TextBox txtNoOfUnsync;
private System.WinForms.Button cmdStart;
private System.WinForms.Label label6;
private System.WinForms.Label label5;
private System.WinForms.TextBox txtThirdTwoCounter1;
private System.WinForms.Label label3;
private System.WinForms.TextBox txtSecondTwoCounter2;
private System.WinForms.TextBox txtSecondTwoCounter1;
private System.WinForms.Label label2;
private System.WinForms.TextBox txtFirstTwoCounter2;
private System.WinForms.TextBox txtFirstTwoCounter1;
private System.WinForms.Label label1;
//Counter variables for FirstTwoCounter
//will be incremented by FirstTwoCounter Thread
private System.Int32 FirstTwoCounterCnt1=0;
private System.Int32 FirstTwoCounterCnt2=0;
//Counter variables for SecondTwoCounter
//will be incremented by SecondTwoCounter Thread
private System.Int32 SecondTwoCounterCnt1=0;
private System.Int32 SecondTwoCounterCnt2=0;
//Counter variables for ThirdTwoCounter
//will be incremented by ThirdTwoCounter Thread
private System.Int32 ThirdTwoCounterCnt1=0;
private System.Int32 ThirdTwoCounterCnt2=0;
//Counter variables for FourthTwoCounter
//will be incremented by FourthTwoCounter Thread
private System.Int32 FourthTwoCounterCnt1=0;
private System.Int32 FourthTwoCounterCnt2=0;
//Counter variables for FifthTwoCounter
//will be incremented by FifthTwoCounter Thread
private System.Int32 FifthTwoCounterCnt1=0;
private System.Int32 FifthTwoCounterCnt2=0;
//Thread For FirstTwoCounter
private System.Threading.Thread FirstTwoCounterThread;
//Thread For SecondTwoCounter
private System.Threading.Thread SecondTwoCounterThread;
//Thread For ThirdTwoCounter
private System.Threading.Thread ThirdTwoCounterThread;
//Thread For FourthTwoCounter
private System.Threading.Thread FourthTwoCounterThread;
//Thread For FifthTwoCounter
private System.Threading.Thread FifthTwoCounterThread;
//Watches the counters on all the threads and displays whethere the pairs of counters are equal or out of sync
private System.Threading.Thread WatchThread;
private static System.Int32 NoOfUnsync=0;
public Form1 ()
{
//
// 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));
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
public override void Dispose()
{
base.Dispose();
components.Dispose();
//Clean all the threads
if (FirstTwoCounterThread.IsAlive)
{
FirstTwoCounterThread.Abort();
}
if (SecondTwoCounterThread.IsAlive)
{
SecondTwoCounterThread.Abort();
}
if (ThirdTwoCounterThread.IsAlive)
{
ThirdTwoCounterThread.Abort();
}
if (FourthTwoCounterThread.IsAlive)
{
FourthTwoCounterThread.Abort();
}
if (FifthTwoCounterThread.IsAlive)
{
FifthTwoCounterThread.Abort();
}
if (WatchThread.IsAlive)
{
WatchThread.Abort();
}
FirstTwoCounterThread=
null;
SecondTwoCounterThread=
null;
ThirdTwoCounterThread=
null;
FourthTwoCounterThread=
null;
FifthTwoCounterThread=
null;
WatchThread=
null;
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void 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++);
txtFirstTwoCounter2.Text=Int32.ToString(FirstTwoCounterCnt2++);
//Uncomment the following line for proper Synchronization
//Monitor.Exit(this);
//End Of Critical Section
}
}
private void 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++);
txtSecondTwoCounter2.Text=Int32.ToString(SecondTwoCounterCnt2++);
//Monitor.Exit(this);
//Uncomment the following line for proper Synchronization
//End Of Critical Section
}
}
private void 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++);
txtThirdTwoCounter2.Text=Int32.ToString(ThirdTwoCounterCnt2++);
//Monitor.Exit(this);
//Uncomment the following line for proper Synchronization
//End Of Critical Section
}
}
private void 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++);
txtFourthTwoCounter2.Text=Int32.ToString(FourthTwoCounterCnt2++);
//Uncomment the following line for proper Synchronization
//Monitor.Exit(this);
//End Of Critical Section
}
}
private void 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++);
txtFifthTwoCounter2.Text=Int32.ToString(FifthTwoCounterCnt2++);
//Uncomment the following line for proper Synchronization
//Monitor.Exit(this);
//End Of Critical Section
}
}
private void WatchCounters()
{
while(true)
{
Thread.Sleep(50);
//Begin Of Critical Section
//Uncomment the following line for proper Synchronization
//Monitor.Enter(this);
if(FirstTwoCounterCnt1!=FirstTwoCounterCnt2)
{
label2.Text="OutOfSync";
txtNoOfUnsync.Text=Int32.ToString(NoOfUnsync++);
}
if(SecondTwoCounterCnt1!=SecondTwoCounterCnt2)
{
label3.Text="OutOfSync";
txtNoOfUnsync.Text=Int32.ToString(NoOfUnsync++);
}
if(ThirdTwoCounterCnt1!=ThirdTwoCounterCnt2)
{
label5.Text="OutOfSync";
txtNoOfUnsync.Text=Int32.ToString(NoOfUnsync++);
}
if(FourthTwoCounterCnt1!=FourthTwoCounterCnt2)
{
label8.Text="OutOfSync";
txtNoOfUnsync.Text=Int32.ToString(NoOfUnsync++);
}
if(FifthTwoCounterCnt1!=FifthTwoCounterCnt2)
{
label9.Text="OutOfSync";
txtNoOfUnsync.Text=Int32.ToString(NoOfUnsync++);
}
//Uncomment the following line for proper Synchronization
/Monitor.Exit(this);
//End Of Critical Section
}
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container ();
this.txtSecondTwoCounter1 = new System.WinForms.TextBox ();
this.cmdExit = new System.WinForms.Button ();
this.cmdStart = new System.WinForms.Button ();
this.label10 = new System.WinForms.Label ();
this.txtSecondTwoCounter2 = new System.WinForms.TextBox ();
this.label2 = new System.WinForms.Label ();
this.label11 = new System.WinForms.Label ();
this.txtFourthTwoCounter1 = new System.WinForms.TextBox ();
this.txtNoOfUnsync = new System.WinForms.TextBox ();
this.txtFirstTwoCounter1 = new System.WinForms.TextBox ();
this.txtFirstTwoCounter2 = new System.WinForms.TextBox ();
this.label4 = new System.WinForms.Label ();
this.txtFifthTwoCounter2 = new System.WinForms.TextBox ();
this.txtFifthTwoCounter1 = new System.WinForms.TextBox ();
this.label7 = new System.WinForms.Label ();
this.txtFourthTwoCounter2 = new System.WinForms.TextBox ();
this.label8 = new System.WinForms.Label ();
this.label9 = new System.WinForms.Label ();
this.label1 = new System.WinForms.Label ();
this.txtThirdTwoCounter2 = new System.WinForms.TextBox ();
this.label3 = new System.WinForms.Label ();
this.label5 = new System.WinForms.Label ();
this.label6 = new System.WinForms.Label ();
this.txtThirdTwoCounter1 = new System.WinForms.TextBox ();
//@this.TrayHeight = 0;
//@this.TrayLargeIcon = false;
//@this.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";
cmdExit.Click +=
new System.EventHandler (this.cmdExit_Click);
cmdStart.Location =
new System.Drawing.Point (320, 224);
cmdStart.Size =
new System.Drawing.Size (72, 32);
cmdStart.TabIndex = 12;
cmdStart.Text = "Start";
cmdStart.Click +=
new System.EventHandler (this.cmdStart_Click);
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;
label7.Click +=
new System.EventHandler (this.label7_Click);
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);
this.Text = "Importance Of Synchronization";
this.AutoScaleBaseSize = new System.Drawing.Size (5, 13);
this.ClientSize = new System.Drawing.Size (480, 397);
this.Click += new System.EventHandler (this.Form1_Click);
this.Closing += new System.ComponentModel.CancelEventHandler (this.Form1_Closing);
this.Controls.Add (this.cmdExit);
this.Controls.Add (this.label11);
this.Controls.Add (this.label8);
his.Controls.Add (this.txtFifthTwoCounter2);
this.Controls.Add (this.txtFifthTwoCounter1);
this.Controls.Add (this.label4);
this.Controls.Add (this.label10);
this.Controls.Add (this.label9);
this.Controls.Add (this.txtFourthTwoCounter2);
this.Controls.Add (this.txtFourthTwoCounter1);
this.Controls.Add (this.label7);
this.Controls.Add (this.txtNoOfUnsync);
this.Controls.Add (this.cmdStart);
this.Controls.Add (this.label6);
this.Controls.Add (this.label5);
this.Controls.Add (this.txtThirdTwoCounter2);
this.Controls.Add (this.txtThirdTwoCounter1);
this.Controls.Add (this.label3);
this.Controls.Add (this.txtSecondTwoCounter2);
this.Controls.Add (this.txtSecondTwoCounter1);
this.Controls.Add (this.label2);
this.Controls.Add (this.txtFirstTwoCounter2);
this.Controls.Add (this.txtFirstTwoCounter1);
this.Controls.Add (this.label1);
}
protected void cmdExit_Click (object sender, System.EventArgs e)
{
Close();
}
protected void Form1_Closing (object sender, System.ComponentModel.CancelEventArgs e)
{
}
protected void label7_Click (object sender, System.EventArgs e)
{
}
protected void cmdStart_Click (object sender, System.EventArgs e)
{
FirstTwoCounterThread.Start();
SecondTwoCounterThread.Start();
ThirdTwoCounterThread.Start();
FourthTwoCounterThread.Start();
FifthTwoCounterThread.Start();
WatchThread.Start();
}
protected void Form1_Click (object sender, System.EventArgs e)
{
}
/// <summary>
/// The main entry point for the application.
/// </summary>
public static void Main(string[] args)
{
Application.Run(
new Form1());
}
}
}

This article is update and edited to RTM (.NET Final) by Zhanbo Sun.


Similar Articles