Introduction
A thread
is a sequence of instructions executed within the context of a process.
MultiThreading is achieved when a� program uses multiple execution threads
allowing each thread to share the CPU concurrently depending on the priority
assigned to these threads. This helps in the optimum usage of System Resources.
Our application shows how multiple threads (in our case two) run on different
level of priorities. We will discuss the whole program part by part.
Code Analysis
using System;
using System.Drawing;
using System.WinForms;
using System.Threading;
We
make use of the above mentioned NameSpaces for our application.
System.WinForms
and System.Drawing
are used to handle the Graphical User Interface. The Progress Bar and
Buttons we make all come under and all come as a part of the System.WinForms
namespace.
By System.Drawing
we take care of all the positioning and size of the WinForm
controls.
Point
and Size
are the built-in objects supported by
the
Drawing
namespace.
The System.Threading
namespace provides classes and interfaces that enable multi-threaded
programming. This namespace includes a ThreadPool
class that manages groups of
threads, a Timer class that enables a delegate to be called after a specified
amount of time, and a Mutex
class for synchronizing mutually-exclusive threads.
I
also provides classes for thread scheduling, wait
notification, and deadlock resolution.
public class PgBar : Form
{
static int tp1, tp2;
Thread thread , td;
ProgressBar pg1 = new ProgressBar();
ProgressBar pg2 = new ProgressBar();
Button bt = new Button();
Button bt1 = new Button();
Button bt2 = new Button();
This
is the declaration part of the Application. Here we are basically declaring
public variables and objects. We declare two threads using the Thread
class and the other control functions like Progress Bar, ComboBox and
Buttons.
static ComboBox cb1 = new ComboBox();
ComboBox.ObjectCollection c1 = new ComboBox.ObjectCollection(cb1);
static ComboBox cb2 = new ComboBox();
ComboBox.ObjectCollection c2 = new ComboBox.ObjectCollection(cb2);
Note
that the ComboBox declaration is different from those that you
observe in ProgressBar and Button. This is because
the statement
static ComboBox cb1 = new ComboBox();
just
creates an instance of the ComboBox, and if you want to add items
to this you will have to declare an ComboBox.ObjectCollection
object.
ComboBox.ObjectCollection c1 = new ComboBox.ObjectCollection(cb1);
�The ComboBox.ObjectCollection
constructor
takes in a ComboBox
object, which becomes the owner of the ObjectCollection
.
Now for inserting items into the ComboBox
you will have
to insert the items in the ObjectCollection
. For Example:
c1.Insert(0,"Lowest");
This
is the Main
function for the application. It creates an instance
of this class that is PgBar. And the second statement runs the
application.
public static void Main()
{
PgBar pgbApp = new PgBar();
Application.Run(pgbApp);
}
public PgBar()
{
this.Text = "THE THREADER-> NARENDAR AND ANSHUMAN";
this.Size = new Size(500,200);
this.BackColor = Color.Black;
this.ForeColor = Color.White;
pg1.Maximum = 300;
pg1.Minimum = 0;
pg1.Step = 20;
pg1.Location = new Point(10,10);
pg1.Size = new Size(300,20);
pg1.BackColor = Color.White;
pg1.ForeColor = Color.Gray;
pg2.Maximum = 300;
pg2.Minimum = 0;
pg2.Step = 20;
pg2.Location = new Point(10,40);
pg2.Size = new Size(300,20);
pg2.BackColor = Color.White;
pg2.ForeColor = Color.Gray;
bt.Text = "START";
bt.Location = new Point(40,80);
bt.Size = new Size(60,20);
bt1.Text = "CLEAR";
bt1.Location = new Point(120,80);
bt1.Size = new Size(60,20);
bt2.Text = "EXIT";
bt2.Location = new Point(200,80);
bt2.Size = new Size(60,20);
c1.Insert(0,"Lowest");
c1.Insert(1,"Below Normal Lowest");
c1.Insert(2,"Normal");
c1.Insert(3,"Above Normal");
c1.Insert(4,"Highest");
cb1.SelectedIndex = 0;
cb1.Location = new Point(320,10);
c2.Insert(0,"Lowest");
c2.Insert(1,"Below Normal");
c2.Insert(2,"Normal");
c2.Insert(3,"Above Normal");
c2.Insert(4,"Highest");
cb2.SelectedIndex = 0;
cb2.Location = new Point(320,40);
this.Controls.Add(bt);
this.Controls.Add(bt1);
this.Controls.Add(bt2);
this.Controls.Add(pg1);
this.Controls.Add(pg2);
this.Controls.Add(cb1);
this.Controls.Add(cb2);
The
above block of code defines all the Graphical Controls. We create the controls
by giving definitions to all the controls declared during the declaration
stage.
this.Controls.Add(bt);
The
above statement adds the Button bt
to the Form. The keyword this
here corresponds to the present
Form.
bt.Click+= new EventHandler(this.timer1_Tick);
bt1.Click+= new EventHandler(this.timer1_Tick);
bt2.Click+= new EventHandler(this.timer1_Tick);
These
statements basically define the event handling method for the buttons in the
form. When you create an EventHandler
delegate, you specify the method
that will handle the event, which in our case is - timer1_Tick
.
Once the delegate is assigned to the event, the handler method is automatically
invoked whenever the event is triggered. So once you click any of the buttons
the method time1_Tick
is invoked.
The
syntax of the EventHandler
delegate specifies the signature for the
event handler, where sender is the source of the event and e is
an Event object. So the EventHandler
method timer1_Tick
takes
in the source that is the object that triggers the method and an event object.
The timer1_Tick
method's access modifier is protected
and
it returns void, that is, nothing.
protected void timer1_Tick (object sender, System.EventArgs e)
If the Button bt
, which corresponds to Start
in the application, is
clicked this block of code will get executed.
if(sender==bt)
{
pg1.Value = 0;
pg2.Value = 0;
tp1 = cb1.SelectedIndex;
tp2 = cb2.SelectedIndex;
thread = new Thread(new ThreadStart(Display));
place(ref thread,tp1);
thread.Start();
td = new Thread(new ThreadStart(Displaytd));
place(ref td,tp2);
td.Start();
}
pg1
is an
instance of ProgressBar
, and pg1.Value
is the property of
ProgressBar
that assigns or gets the value of the current position the ProgressBar
. cb1
is an instance of ComboBox
, and SelectedIndex
indicates the [zero based] index of the currently selected item in the combos
list. The application runs the two ProgressBars
as two threads and the
two ComboBox
allows the user to set the priorities at runtime for these
ProgressBars
.
We create instances for two threads - thread and td.
The constructor of Thread
class takes instance of� a ThreadStart
class.
The ThreadStart
class is a delegate that points to the method
that should be executed first when a thread is started. thread invokes
Display
method and td invokes Displaytd
. �The selected value in
ComboBox
is captured in a
static int variables tp1 and tp2. We pass the reference of the
threads and the corresponding index value to method place()
. place()
method will be explained later. <threadobject>.start()
starts
executing the thread.
if(sender==bt1)
{
pg1.Value=0;
pg2.Value=0;
}
If the Button bt1
, which corresponds to Clear
in the application, is
clicked this block of code will get executed. It just assigns the values to
both the ProgressBar
instances as 0, thereby, clearing both the ProgressBar
.
if(sender==bt2)
{
Application.Exit();
if(td.IsAlive)
td.Abort();
if(thread.IsAlive)
thread.Abort();
}
If the Button bt2
, which corresponds to Exit
in the application, is
clicked this block of code will get executed. <threadobject>.IsAlive
returns true or false depending on whether the Thread
is running
or not.� This checking is must as otherwise it throws ThreadStateException
.
<threadobject>.Abort()
method exits the thread. The Application is closed and
both the threads (if they are alive) are aborted.
protected void Display()
{
for(long i = 0l; i<20000000; i++)
{
if(i%1000000 == 0)
{
if(pg1.Value != 300)
pg1.Value += 20;
else
thread.Abort();
}
}
}
protected void Displaytd()
{
for(long i = 0l; i<20000000; i++)
{
if(i%1000000 == 0)
{
if(pg2.Value != 300)
pg2.Value += 20;
else
td.Abort();
}
}
}
Both Display()
and Displaytd()
methods effectively do exactly the same
task. We went in for this because we wanted to display how two identical
threads, when assigned different priorities, work. With every step the value of
ProgressBars
are incremented by 20 till the value of ProgressBars
reach
300 and then the thread aborts.
public void place(ref Thread p, int x)
{
switch(x)
{
case 0:
p.Priority = ThreadPriority.Lowest;
break;
case 1:
p.Priority = ThreadPriority.BelowNormal;
break;
case 2:
p.Priority = ThreadPriority.Normal;
break;
case 3:
p.Priority = ThreadPriority.AboveNormal;
break;
case 4:
p.Priority = ThreadPriority.Highest;
break;
}
}
place()
method takes in a reference to
a thread and the (int) index value captured through the ComboBox
s as
its arguments. Then we assign prioities to the threads according to the value
selected in the ComboBox
.
Notes:
Unlike
in Java where you can have priorities from 1 to 10 corresponding to
MIN_PRIORITY
to MAX_PRIOITY
. You can assign any priority within this range
i.e., 1 to 10. Whereas in C# you have only five of them. Lowest (0),
BelowNormal (1), Normal (2), AboveNormal (3) and Highest (4).