Issue dated - 10th February 2003

-


CURRENT ISSUE
INDIA NEWS
INDIA TRENDS
STOCK FILE
OPINION
FOCUS
E-BUSINESS
COMPANY WATCH
TECHSPACE
TECHNOLOGY
PRODUCTS
EVENTS
COLUMNS
TECH FORUM

THE C# COLUMN

BETWEEN THE BYTES
TECHNOLOGY
SPECIALS <NEW>
HMA BANKBIZ
EC SERVICES
ARCHIVES/SEARCH
IT APPOINTMENTS
WRITE TO US
SUBSCRIBE/RENEW
CUSTOMER SERVICE
ADVERTISE
ABOUT US

 Network Sites
  IT People
  Network Magazine
  Business Traveller
  Exp. Hotelier & Caterer
  Exp. Travel & Tourism
  Exp. Backwaters
  Exp. Pharma Pulse
  Exp. Healthcare Mgmt.
  Express Textile
 Group Sites
  ExpressIndia
  Indian Express
  Financial Express

 
Front Page > TechSpace > Story Print this Page|  Email this page

Creating multithreaded applications

The C# Column - Yashawant Kanetkar

In a broad sense, multithreading can be thought of as the ability to perform several jobs simultaneously. For example, while working in Windows, we can simultaneously carry out different jobs like printing a document on the printer, receiving e-mails, downloading files and compiling programs. All these operations are carried out through different programs, which execute concurrently in memory.

Even though it may appear that several tasks are being performed by the processor simultaneously, in actuality it is not so. This is because in a single-processor environment, the processor divides the execution time equally among all the running threads. Thus each thread gets the processor’s attention in a round-robin manner. Once the time-slice allocated for a thread expires, its state and values are recorded, the operation that it is currently performing is put on hold and the processor directs its attention to the next thread. Thus at any given moment if we take a snapshot of memory we will find that only one thread is being executed by the processor. Thread switching happens so fast that we get a false impression that the processor is executing several threads simultaneously.

Multithreading has several advantages to offer. These are listed below:

Responsiveness: Take the example of MS-Word. Here, had the spell checker and the grammar checker not run as different threads, we would have been required to write the document and then submit it to each checker later. This would have resulted in low responsiveness. But since the checkers run in different threads, our document gets checked as we type, thereby increasing the responsiveness of the application.

Organisation: Threading simplifies program organisation. In the ‘File Copy’ example if both the operations—playing the animation and the actual copying were run in the same thread, then after copying a few thousand bytes we would be required to play the next frame of animation. If we run the copying code and animation code in separate threads we can avoid cluttering the copying code with animation code and vice versa.

Performance: Many a time it happens that a program needs to wait for user input or has to give some output. The I/O devices are generally slower than the processor. So the application waits for the I/O operation to finish first. If instead, we use another thread for the I/O operation, the processor time can be allotted to other important tasks independent of the I/O operation, thereby increasing the performance.

Launching threads
Now that we know what threads are, let us now see how they can be created. Starting a thread is very simple. The following statements launch a new thread.

ThreadStart ts = new ThreadStart (func);
Thread t1 = new Thread();
t1.Start();

While creating a thread, we must specify which method should get executed when the thread starts execution. If we wish that a static method func( ) should get executed in the thread, we would have to wrap its address in a delegate and pass it to the constructor of the Thread class. For this, we have to use a predefined .NET delegate class called ThreadStart. The signature of this delegate is such that it returns a void and does not accept any arguments. Hence func( ) also needs to have the same signature. To start the thread we must call the Start( ) method of the Thread class. Both the Thread class and the ThreadStart delegate belong to the System.Threading namespace hence we need to write using System.Threading at the beginning of any program.

Let us now see an example where multithreading is actually needed. Here we plan to make a simple game. The UI of the game is given in the adjacent screen shot:

This application consists of two buttons named start and hit, and three textboxes named num1, num2 and num3.

The user needs to click on the start button to start the game. As soon as this button is clicked, random numbers would get displayed on the three textboxes. Now at any instance if the user clicks on the hit button, the display of numbers stops. If the numbers turn out to be the same the user hits the jackpot.

It is impossible to generate and display the random numbers in the three textboxes simultaneously in the main thread. If we attempt to do so, numbers in the second textbox would get generated only after generating and displaying numbers in the first textbox. So here if we want concurrent functionality, we need to generate and display the numbers for the textboxes in three different threads. On clicking the start button, the three threads get launched as shown in the following code snippet:

private void start_Click(object sender, System.EventArgs e)
{
	t1 = new Thread (new ThreadStart (this.display1));
	t1.Start();
	t2 = new Thread (new ThreadStart (this.display2));
	t2.Start();
	t3 = new Thread (new ThreadStart (this.display3));
	t3.Start();
}

We have added the references t1, t2 and t3 of the Thread class as data members of the Form1 class. The display1( ) method is given below.

public void display1()
{
   int j = r.Next (0, 50);
   int k = r.Next (50, 100);
   for (int i = j ; i <= k ; i++)
   {
	   num1.Text = i.ToString();
	   Thread.Sleep(200);
	}
}

Here we have used an object of the Random class referred to by r that we also added as a data member of the Form1 class. Using this object we have created two random numbers and displayed all numbers lying between the two in the textbox. The display2( ) and display3( ) methods are on the same lines. Hence random numbers keep on getting displayed simultaneously on the three textboxes. Now the user needs to click the hit button. The handler for the hit button is given below:

private void hit_Click(object sender, System.EventArgs e)
{
		t1.Abort();
		t2.Abort();
		t3.Abort();
		if (int.Parse (num1.Text) == int.Parse(num2.Text) && 
		int.Parse(num2.Text) == int.Parse(num3.Text))
		MessageBox.Show( “Jackpot” );
}

Here we have aborted the threads using the Abort( ) method, compared the numbers and displayed a message if they are same.

Thread states
From the time a thread is started until it gets terminated the thread undergoes many transitions and is said to be in at least one of the several ‘thread states.’

A thread can be in one or more of the following states at any given time: Unstarted, Running, Suspended, WaitSleepJoin, SuspendRequested, Aborted, AbortRequested, Stopped and StopRequested. All these states are members of the ThreadState enumeration declared in System.Threading namespace. Let us now discuss these states.

Unstarted: A thread is said to be in the Unstarted state when it is first created. It remains in this state until the program calls the Start() method of the Thread class.

Running: As soon as the Start() method is called, the thread starts executing and is said to be in the Running state. This means that the thread will now start getting CPU time slots.

Suspended: When a running thread’s Suspend() method is called, the thread goes into the Suspended state and would stop receiving CPU time-slots.

WaitSleepJoin: At times we may want to prevent our thread from getting CPU cycles till passage of some time or make our thread wait till some other thread completes some operation or wait till some other thread terminates.

We can achieve these three scenarios by calling the methods Thread.Sleep( ), Monitor.Wait( ) and Thread.Join( ) methods respectively on our thread. Upon calling one of these three methods, our thread enters the WaitSleepJoin state.

Once in this state we can transition out of it in the following three ways:

(a) The sleeping time specified by the Sleep() method expires.

(b) Another thread calls the Thread.Interrupt() method before the sleeping time expires.

(c) Another thread calls the Monitor.Pulse() method or Monitor.PulseAll() method. Monitor.Pulse() moves the waiting thread into the Running state. Monitor.PulseAll() method moves the thread along with all the other waiting threads into the Running state.

All the above three ways move the thread from the WaitSleepJoin state to the Running state.

Stopped: When a thread completes its execution, it goes into the Stopped state.

Aborted: Whenever an exception is thrown and the thread stops executing abruptly it goes into the Aborted state.

AbortRequested: The AbortRequested state is reached when a thread is in another state but is being requested to abort. As soon as it comes out of the present state, it gets aborted.

SuspendRequested: The SuspendRequested state is reached when a thread is in another state but is being requested to suspend using the Suspend( ) method. As soon as it comes out of the present state, it gets suspended.

StopRequested: The StopRequested state is reached when a thread is being requested to stop. There is no method available that we can invoke to manually force our thread in this state.

Yashavant Kanetkar, one of the first Express Computer columnists, is an established software expert, speaker and author with several best-sellers to his credit, including titles like “Let Us C” and the “Fundas” series. Contact him at kanet@nagpur.dot.net.in
<Back to top>


© Copyright 2000: Indian Express Group (Mumbai, India). All rights reserved throughout the world. This entire site is compiled in
Mumbai by The Business Publications Division of the Indian Express Group of Newspapers.
Please contact our Webmaster for any queries on this site.