SlideShare a Scribd company logo
C# - Classes
Contents
Authors
Introduction
Section I - Threads
1. Threads, Events and Mutextes
2. Internet Classes
3. Remoting
Section II - Winforms
4. Controls
5. Data Handling
6. Printing
Section III - Xml
7. Xml Classes
8. The DTD
9. Xml Data Document
10. Xml Documentation
Authors
Vijay Mukhi (vmukhi@vsnl.com) is one of the pioneers of the Indian Infotech Industry. For years, he has been the first to
teach the emerging technologies in India thus ensuring that India always has people trained in technologies that the world
requires. Vijay has written over 80 books on computers and programming over the last eight years on subjects ranging from
C, C++ (The Odyssey Series) to Animation and Networking to Java to C#. Vijay abhors complexities and hence his books
showcase the most difficult concepts explained through small programs, thereby giving a good understanding. Microsoft's
.Net technologies is what Vijay is now focusing on and he aims at writing volumes on it. His knowledge on .Net Technologies
is clearly visible in his four books where he explains the different concepts of the C# programming language in the most
simplified form.
Vinay Kalantri (vinaykalantri@yahoo.co.in) is a bright and enterprising software expert who has completed an extensive
course in Business Management from a reputed University in the United States of America. He is presently undergoing
rigorous training in software development in frontline applications.
Sonal Mukhi (svmukhi@yahoo.com) is a freelance programmer having a widespread exposure to computer techniques and
languages. Sonal has done groundbreaking work on various Internet Technologies like Java, ActiveX, Perl, C# and more.
She has co-authored a few books on computer programming too.
Introduction
This book presents myriad fascinating concepts about C# classes. It is classified into three sections, with each of them
converging on distinct facets of classes available in the .Net framework
The curtains are raised with the chapter on Threads in Section I, which presents a nascent introduction to this topic. The
topics of Events and Mutexes are also explored in detail.
The next chapter is on the Internet related classes. Here, the utility of the Web classes and their role in building server and
client applications are highlighted.
The last chapter in this section takes on a different hue. It encapsulates the crux of writing programs to implement the
concept of 'remoting'. This involves the composition of a client and a server program on different machines.
The spotlight then moves on to the concept of Winforms in Section II. This chapter is replete with practical and useful
insights into how Winforms can be put to optimum use in the .Net world. The C# language provides the facility of generating
user-interfaces having aesthetic appeal, either by implementing the ready-to-use Form Controls, or by using controls crafted
by us, in order to receive inputs from an end user.
The subsequent chapter in this section delves upon the Database Controls. This chapter has been sedulously crafted, to
capture the essence of this significant activity and to reveal its intricate details.
The ubiquitous task of printing is the focus of the next chapter. The contents of this chapter will equip you to print output with
practiced panache.
The last section is devoted to XML, which is the most hyped language in the current market scenario. An XML file embodies
an assortment of components, which will be unraveled, one at a time, in the chapters of this section.
At the outset, the common XML classes have been highlighted, to provide an introduction to XML concepts, which are used
while programming in the C# language.
The next two chapters focus on DTD, which is an acronym for Data Type Definition, and also on the XML Data Document.
They provide information on the various elements employed while generating an XML file.
The topic of XML Documentation provides a hiatus from the preceding abstruse topics. It has been laced with effervescent
text and examples to liven up the proceedings.
We have applied utmost perspicacity to ensure that accurate, useful and relevant explanations, laced with lucid and practical
examples, be presented to expound the various concepts to both, the amateur and the proficient programmer alike.
We assure you that, by the time you disembark from this intellectual voyage of discovery, the various concepts that have
been presented, are doubtlessly bound to create an indelible imprint on your minds.
Requirements
The software requirements to successfully run all the programs in this book are
• Operating System - Windows 2000
• A Web Server preferably Microsoft IIS ver 5.0
• SQLServer 2000 (Evaluation Edition)
• Internet Explorer 5.5
• .Net Framework SDK Beta 2 (111 MB)
Internet Explorer 5.5 can be downloaded off the Microsoft site
• http://www.microsoft.com/windows/ie/download/ie55sp1.htm
Net Framework SDK Beta 2 can be downloaded off the Microsoft site
• http://download.microsoft.com/download/VisualStudioNET/Trial/2.0/W982KMeXP/EN-US/setup.exe
Alternatively, you can visit the download section at Microsoft ( http://msdn.microsoft.com/downloads/default.asp ) and
download the .Net framework SDK Beta 2 under the Software Development Kit option.
SQLServer 2000
While installing the evaluation edition of SQLServer 2000, we have chosen the default selected settings. The only
modification made is in the Authentication Dialog Box.
You see two options
• Windows Authentication mode
• Mixed mode (Windows Authentication and SQL Server Mode)
The default option selected is Windows Authentication mode. We have instead selected Mixed mode (Windows
Authentication and SQL Server Mode). Once this option is selected, the password text boxes for the 'sa' user gets activated.
As we would prefer using a blank password in our programs, we select Blank Password. On selecting this option, the text
boxes get disabled again.
Acknowledgements
The many individuals who have worked together to produce this great work of art and motivated me all the way need a
mention here. Their bright ideas, inspiration, support has made me a lot more stronger and wiser.
First and foremost, thanks to Manish Jain, BPB Publications for publishing the book.
To my co-authors, Sonal and Vinay who have put in a lot of hard work to complete the work assigned to them.
To Tanuja Sodhi, an ex-Naval Officer from the first batch of lady officers and an MBA from Jamnalal Bajaj, for editing the
book. She is presently freelancing as a creative writer.
To Altaf Hemani and Kishore Rohra, for their creativity in designing the cover in a given short time.
Thanks to Manish Purohit for putting in all the time he had to verify the code with the explanations and then giving the book
a good look and feel.
To Pradeep Mukhi and Shivanand Shetty, who have always been there, as a source of inspiration and encouragement.
My Mother, Shana Aunty and a long list of friends need a mention here for their patience and cooperation on this book
while it was being written.
-Vijay Mukhi
1
Threads, Events and Mutexes
Threads operate on the premise that the computer is definitely more expeditious than a human at executing tasks, resulting
in the computer idling away most of its processing time, waiting for the human operator. Threads are a means of overcoming
this wastage of processing time. They perform multiple tasks on a computer in rapid succession, thereby, creating the
illusion of these tasks being executed simultaneously. No application can ever be comprehensive without employing threads.
Before we try to infer what a thread does in the programming context, let us rummage through a few examples given below.
Without being discursive, let us venture out on our odyssey of understanding the concept of a thread with the assistance of a
very diminutive program.
a.cs
using System.Threading;
public class yyy
{
public static void abc()
{
System.Console.WriteLine("Hi");
}
}
public class zzz
{
public static void Main()
{
ThreadStart ts = new ThreadStart(yyy.abc);
Thread t = new Thread(ts);
System.Console.WriteLine("Before Start");
t.Start();
}
}
Output
Before Start
Hi
This one is bound to leave you astonished because, we had earlier talked about starting out with a 'dimunitive' program.
However, by no stretch of the imagination can the above program qualify as miniscule. Besides, the only work accomplished
by this function is that it calls the static function abc, which in turn displays 'Hi'.
In Main, we create an object ts, which is an instance of the class ThreadStart, which is derived from Delegate. Therefore,
even though ThreadStart is a class, it also happens to be a delegate, whose constructor is given a static function called abc.
Function abc is placed in the yyy class so that other classes can also use it. The program will work in a similar manner even
if the static function is placed in class zzz.
Next, we create another object t, which is an instance of Thread. The constructor of this object is given a ThreadStart object
ts. Indirectly, ts stands for the static function yyy.abc since it is a delegate.
So far, tranquility prevails and nothing transpires. The function yyy.abc too does not get called. But, as soon as we call Start
off the thread, the function abc gets catapulted into action. Thus, the function abc is called only when the Start function is
called. This is really no big deal. Note that classes beginning with Thread belong to the System.Threading namespace.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("Hi");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
}
}
Output
Hi
The above program is similar to the previous one and resembles the samples supplied by Microsoft. The function abc to be
called, is non-static and hence, an object name is needed to reference it. The ThreadStart delegate object is directly passed
as a parameter to the Thread constructor.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=3;i++)
{
System.Console.Write(i + " ");
}
}
public void pqr()
{
for ( int i = 0; i<=3;i++)
{
System.Console.Write(i+ "...");
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.pqr));
t.Start();
t1.Start();
}
}
Output
0 1 2 3 0...1...2...3...
The example embodies a very large amount of code. However, it does not create any fresh ripples in our pond of
knowledge. We have merely created two Thread objects t and t1, and passed their constructors a different delegate or
function name, i.e. abc and pqr, respectively. Thereafter, the Start function has been called in t and t1. Here, the function
abc gets called, which displays four numbers. Thereafter, the function pqr gets called, which also displays four numbers, but
with three dots.
You may wonder with trepidation as to when you will bite into the real meat. Keep your impatience in abeyance for a little
while !
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=3;i++)
{
System.Console.Write(i + " ");
Thread.Sleep(1);
}
}
public void pqr()
{
for ( int i = 0; i<=3;i++)
{
System.Console.Write(i+ "...");
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.pqr));
t.Start();
t1.Start();
}
}
Output
0 0...1 1...2 2...3 3...
Now, we are at the threshold of excitement. By adding the function Sleep, which is a static function in the Thread class, the
functions abc and pqr get called simultaneously, although not sequentially. This is how the concept of a thread is
implemented, i.e. it empowers your computer to accomplish multiple jobs at the same time. This process is also termed as
multi-tasking.
Take the case of Microsoft Word. When you attempt to save a file, irrespective of the size of the file, Word appears to
consume the same amount of time in completing this task. To expect it to save a 10MB file within a very short time period is
a thought fraught with absurdity and contrary to reason. Actually, what the Word program does is that it creates a thread and
then solicits the thread to save the file. While the thread is saving that file, another thread waits for the user to type
something. Hence, the user is emancipated to continue working with Word. Thus, in effect, two tasks are being executed
concurrently without the user being cognizant of it ! The same mechanism is employed by Excel and other similar products.
Any application under Windows runs in its own thread. Thus, if two programs are launched, there will be two threads
running. The operating system refrains from playing favorites and gives an equal amount of time to each thread to execute.
If there are two threads co-existing, then, out of every minute of processing time available, each of them will be allotted 30
seconds to execute. If a third program is now executed, a new thread will be launched and each of the three threads will be
allotted only 20 seconds of the processor time per minute to execute.
If, instead of running a third program, what if the second program itself creates a thread ? As before, this will result in the
creation of a third thread and each thread will be allotted 20 seconds of time. The resultant effect would be that that the first
program will be allotted 20 seconds of time, whereas the second program will get 40 seconds per minute of the processor
time. Thus, the larger number of threads that a program creates, more will be the processor time allotted to it. If you crave
for more time and attention from your computer, desist from throwing a tantrum. Instead, generate greater number of
threads.
The computer allots a specific amount of time to each thread and then puts it to sleep. Thereafter, it executes another
thread. The time given to each thread to execute its code is designated as a Time Slice. This allocation of Time Slices
occurs so swiftly that each thread suffers from the hallucination that it enjoys the undivided attention of the computer.
The static function Sleep in the Thread class facilitates this process. Sleep is like the sandman. It puts the thread to sleep for
a certain number of milliseconds, as specified in its parameter. In this case, it is 1 millisecond. In the earlier example, in a
single time slice, the Thread executed all the code and the function completed execution. In this case, the Sleep delays it
long enough for the next thread to execute, and thus, the code in the functions get called one after the other.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=3;i++)
{
Thread t2 = Thread.CurrentThread;
System.Console.Write(i + "." + t2.Name + " ");
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Name="One";
t1.Name="Two";
t.Start();
t1.Start();
}
}
Output
0.One 0.Two 1.One 1.Two 2.One 2.Two 3.One 3.Two
Here, we have provided mental catharsis by simplifying the program. What we actually have done is given the same function
name abc to our delegate. We have also used the property Name of the Thread class to assign a distinct name to each
thread, i.e. One and Two respectively. Under normal circumstances, the names assigned are pre-ordained by the system.
Now, both the threads will call the same function abc. How do we determine as to which thread is calling the function abc?
The Thread class can have members, which are either static or instance. CurrentThread is a static read-only property that
returns a thread object, which represents the thread that has currently called the function. Here, Thread t2 will either
represent t or t1, and the property Name will display the name of the thread executing the function.
a.cs
using System.Threading;
public class zzz : Thread
{
}
Compiler Error
a.cs(2,14): error CS0509: 'zzz' : cannot inherit from sealed class 'System.Threading.Thread'
The Thread class is a sealed class, therefore we cannot derive from it. The designers of the Thread class at Microsoft have
held very doctrinaire opinions, in that, they believe that they have envisaged all the possible features required in this class.
Thus, they have not provided any facility to override or modify it. Therefore, we are constrained to use the Thread class
exactly as provided, without introducing any code that will complement or add to or subtract from the code of the Thread
class. For your information, the Thread class in turn is derived from the interface ISerializable.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("Hi");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine(t.IsAlive);
t.Start();
System.Console.WriteLine(t.IsAlive);
t.Abort();
System.Console.WriteLine(t.IsAlive);
}
}
Output
False
True
Hi
False
The Thread class has a property called IsAlive that reveals the current state of the Thread. When we create an object that
looks like Thread, the thread is in a dead state and hence, the IsAlive property has a value of False. Start breathes life into
the thread and executes through the delegate abc. The thread now comes alive, but the code in the thread function gets
executed only after the subsequent WriteLine function, which displays the value of IsAlive as True. When we stop or Abort
the Thread, the thread dies and the value of the property IsAlive reverts back to False. Thus, IsAlive can hold only one of the
two values, False for dead or True for alive.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("Hi");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
while ( !t.IsAlive )
System.Console.WriteLine("hi1");
}
}
Output
Hi
In today's world, we are working on extremely fast machines. When we execute t.Start(), the thread is brought to life in a
fraction of a second. Hence, the while loop is not executed because the condition becomes false immediately. Had the
machine been slower, the while loop may have got called a few times, as it would have taken some time before the thread
could have been brought to life. Thus, the speed of execution may vary, depending upon the speed of the machine.
Whenever the sample code creates a thread, it always contains this while loop.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=3 ; i++)
System.Console.Write("Hi " + i + " ");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
System.Console.WriteLine("Over");
}
}
Output
Over
Hi 0 Hi 1 Hi 2 Hi 3
The executable, a.exe, runs in its own thread. So, before calling the function Start, we already have one thread running. On
calling the function Start, two threads run concurrently, independent of each other. The second thread executes the function
abc independent of the first thread. The first thread executes the last WriteLine function and then stops, whereas the second
thread continues executing the function abc till there is no more code to call. If, on your machine, the first thread's time slice
gets over before executing the WriteLine function, then some code of the function abc may get executed before Over gets
displayed in the function Main. It is reiterated yet again that, in case of threads, there can be no guarantee as to when the
time slice of a thread will get over. Even the operating system is not sagacious enough to offer any guarantees in this
regard.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=3 ; i++)
System.Console.Write("Hi " + i + " ");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
t.Join();
System.Console.WriteLine("Over");
}
}
Output
Hi 0 Hi 1 Hi 2 Hi 3 Over
The function Join is a blocking function. It makes the program linger at the function Join till the thread finishes execution. Any
code after the Join, in this case the WriteLine function, will be executed only after the thread dies. A blocking function will
wait until the purpose it is waiting for has reached fructification. Thus, if we want to wait for a thread to complete execution,
we use a Join. Join behaves like a party host, who is always the last to leave.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( ; ; ) ;
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
bool b = t.Join(10000);
System.Console.WriteLine("Over " + b);
}
}
Output
Over False
The Join function accepts a number as a parameter, which represents the maximum duration in milliseconds that it should
wait for the thread to complete execution. In our example, the function abc will never end. Thus, the thread t will go on
forever. Therefore, the Join function waits for 10 seconds, gives up and finally returns a False.
Therefore, we are empowered to decide the duration for which we want to wait for the thread to complete execution. Let us
not forget that our application has not yet terminated and is still hanging around in memory. At this stage, if you press Ctrl-
Alt-Del, you will see a list of programs running. Now, select the End Task option for the program called 'a'. An alternative
approach could be to add the Abort function t.Abort() after the WriteLine function.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( ; ; ) ;
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Join();
}
}
Output
Unhandled Exception: System.Threading.ThreadStateException: Thread has not been started.
at System.Threading.Thread.Join()
at zzz.Main()
If there is no thread running, the Join function will throw the exception of ThreadStateException.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
Thread.Sleep(3);
t.Abort();
System.Console.WriteLine("Over");
Thread.Sleep(100);
t.Start();
}
}
Output
abc
Over
Unhandled Exception: System.Threading.ThreadStateException: Thread is running or terminated. Cannot restart.
at System.Threading.Thread.StartInternal(IPrincipal principal, StackCrawlMark & stackMark)
at System.Threading.Thread.Start()
at zzz.Main()
At first, we start the thread t by calling the Start function. Thereafter, we make the main thread sleep for a little while. Then,
we abort the thread and again sleep for a little while, in order to enable the thread to fulfill its last wishes and finally die. Now
that the thread is dead, we try and infuse life into it by calling Start again. A thread, which has died cannot be resuscitated.
Since we have had the audacity to attempt this, the results are nearly cataclysmic, resulting in the generation of an
exception which has to be caught.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
Thread.Sleep(3);
t.Abort();
System.Console.WriteLine("Over");
Thread.Sleep(100);
try
{
t.Start();
}
catch (ThreadStateException e)
{
System.Console.WriteLine("In Exception");
}
}
}
Output
abc
Over
In Exception
The exception thrown is ThreadStateException, which needs to be caught in our code. Otherwise, the runtime message box
is displayed to the user.
The Thread class constructor can throw two types of exceptions:-
• ArgumentNullException - When it is called without a delegate in the constructor.
• SecurityException - When the program does not have permission to create a thread.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine(t.ApartmentState);
t.ApartmentState = ApartmentState.STA;
t.Start();
System.Console.WriteLine(t.ApartmentState);
}
}
Output
Unknown
STA
abc
We all have our own apartments, which are normally done up as per our preferences i.e. 'We are the kings of our castles'.
Threads also have apartments. Any thread can be asked to execute either in a single-threaded apartment or in a multi-
threaded apartment. These values can be established using the property ApartmentState, either once at the beginning, or
while the thread is running. The various values that ApartmentState can assume are as follows:
· STA : Single Threaded Apartment.
· MTA : Multi Threaded Apartment.
· Unknown : Default value assigned when no value is set.
We, however, cannot use numbers for a string. Thus, an enum called ApartmentState has been used. It holds three values
i.e. 0, 1 and 2 corresponding to STA, MTA and Unknown respectively.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
System.Console.WriteLine("abc " + Thread.CurrentThread.IsBackground);
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine("Main " + Thread.CurrentThread.IsBackground);
t.Start();
}
}
Output
Main False
abc False
A thread executes either in the background or in the foreground. The property IsBackground indicates the mode in which the
thread will run. An important point to be noted here is that, a thread which executes in the background automatically shuts
down when its main program quits.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0 ; i<=100; i++)
{
System.Console.WriteLine("abc " + i);
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
System.Console.WriteLine("Main " + Thread.CurrentThread.IsBackground);
t.IsBackground = true;
t.Start();
Thread.Sleep(10);
}
}
Output (t.IsBackground = true)
Main False
abc 0
Output (t.IsBackground = false)
Main False
abc 0
abc 1
abc 2
..
..
abc 100
When you change the true to false in t.IsBackground, the output shows the code of function abc being executed. The for
loop displays values from 0 to 100.
By changing the property IsBackground of a thread to true, the thread terminates when the main program stops. Thus, the
for loop does not have the time to display values upto 100. At times, the program displays abc with a value of 0.
The sleeps are used to demonstrate the effect of the first thread shutting down and the second carrying on execution. On
changing the property IsBackground to false, the thread takes its own sweet time to execute its code without any regard for
the first thread, which may or may not have completed its job. So, the foreground threads behave exactly in the same
manner as the background threads, when the property is initialized to true.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=10;i++)
{
System.Console.Write(i + " ");
Thread.Sleep(1);
}
}
public void pqr()
{
for ( int i = 0; i<=10;i++)
{
System.Console.Write(i+ "...");
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.pqr));
System.Console.WriteLine(t.Priority);
t.Priority = ThreadPriority.Highest;
t1.Priority = ThreadPriority.Lowest;
t.Start();
t1.Start();
}
}
Output
Normal
0 1 2 3 4 0...5 1...6 2...7 3...8 4...9 5...10 6...7...8...9...10...
We are at liberty to decide the duration of the time-slice to be allotted to our thread vis-a-vis other threads. This can be
achieved by setting the Priority property accordingly. By default, the priority level is 2. Hence, we see 'Normal' displayed as
the output. All threads start at this priority level. The ThreadPriority enum comprises of five levels of priority, which are as
follows:
• 0 - Zero
• 1 - BelowNormal
• 2 - Normal
• 3 - AboveNormal
• 4 - Highest
In our program, we have changed the priority of thread t to the highest possible and that of thread t1 to the lowest. As a
result, Thread t is accorded more time than thread t1, and it finishes its for loop much before thread t1 can do so.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
try
{
System.Console.WriteLine("in abc");
for ( ; ; ) ;
}
catch ( System.Exception e)
{
System.Console.WriteLine("in abc Exception " +e.ToString() );
}
finally
{
System.Console.WriteLine("in abc Finally");
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
Thread.Sleep(10);
t.Abort();
}
}
Output
in abc
in abc Exception System.Threading.ThreadAbortException: Thread was being aborted.
at yyy.abc()
in abc Finally
Aborting a Thread while it is busy executing some code generates an exception. Thus, the function abc will be sent an
exception, resulting in a call to the 'catch' and 'finally' clauses. The thread will be terminated after executing the code in the
Catch and the Finally clause.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
try
{
System.Console.WriteLine("in abc");
for ( ; ; ) ;
}
catch ( System.Exception e)
{
System.Console.WriteLine("in abc Exception " +e.ToString() );
}
finally
{
System.Console.WriteLine("in abc Finally");
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Abort();
t.Start();
}
}
Output
(no output)
Aborting a thread before it has started execution does not generate any exceptions, since the thread is in a dead state.
Hence, no code in abc ever gets called. This situation is akin to the one where you don your best attire to watch cricket live
at the stadium, but the show gets ruined due to heavy downpour, resulting in the match being abandoned without a ball
being bowled !
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for (int i = 1 ; i<= 10 ; i++ )
{
System.Console.Write(i + " " );
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
Thread.Sleep(10);
t.Suspend();
System.Console.WriteLine("n After Suspend");
Thread.Sleep(10);
System.Console.WriteLine("Before Resume");
t.Resume();
}
}
Output
1
After Suspend
Before Resume
2 3 4 5 6 7 8 9 10
We are allowed to Suspend a thread executing its code, at any point in time. In the above program, we let the thread run for
a little while and then Suspend it. Thereafter, we Resume it. Thus, the thread is like a puppet in our hands. We can decide
when and which strings to pull and the thread does our biding. If the thread has already been suspended, then Suspending it
once again has no effect, and thus, it does not result in an error. A single Resume is enough to undo a million Suspends.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
for ( int i = 0; i<=3;i++)
{
Thread t2 = Thread.CurrentThread;
System.Console.Write(i + " " + t2.GetHashCode() + " ");
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Start();
t1.Start();
}
}
Output
0 2 0 3 1 2 1 3 2 2 2 3 3 2 3 3
Every thread is assigned a number internally. This number is called the HashCode. Hashing is the process of assigning a
number to an entity so that it can easily be located from a long list. This hash number is useful and is pressed into service
when we are required to keep track of a large number of threads internally.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
Monitor.Enter(this);
for ( int i = 1; i<=5;i++)
{
System.Console.Write(i + " " + Thread.CurrentThread.GetHashCode() + " ");
Thread.Sleep(1000);
}
Monitor.Exit(this);
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Start();
t1.Start();
}
}
Output
1 2 2 2 3 2 4 2 5 2 1 3 2 3 3 3 4 3 5 3
Let us now clarify the abstract concept of the life of a thread with the help of an example.
Any resource that many people desire is called a shared resource. Imagine the chaos that would be caused if five programs
tried to simultaneously use a single network printer for printing, during their respectively time-slices. This would result in the
printer printing a few pages for program 1, then a few pages for program 2, and so on. The printer will keep printing merrily,
but the printed output will all be jumbled up.
Thus, ideally, one program should use a shared resource at a time, till its job is complete. For this, a method has to be
implemented by means of which, unless one program finishes executing some specific code in a function, no other program
should be allowed to execute it. Thus, all other programs would have to wait until the first thread finishes execution.
Let us assume that function abc contains code which sends a request to the printer to print. The thread t gets the first shot at
running abc. The second thread t1 has to wait until thread t finishes execution, even if the duration of executing abc takes
more time than one time slice, due to a large value being assigned as a parameter to the sleep function. This is achieved by
using the static function Enter of the class Monitor.
The function Enter is given an object which refers to the class in which the function resides. From that point onwards, every
thread has to wait at Enter. The barrier lowers only when Exit is called from the Monitor class. Enter acts as a fussy security
guard who decides as to which thread is to be prohibited and which one is to be permitted to execute code. No two threads
can ever enter the Enter function together. It is a rigid one way lane from Enter to Exit. One car is allowed in at one time and
another car can pass through only after the first car leaves Exit. You can see that the names Enter and Exit have been
chosen very aptly.
a.cs
using System;
using System.Threading;
public class ggg
{
};
public class yyy
{
public ggg g1;
public void abc( )
{
Monitor.Enter(g1);
for ( int i = 1; i <= 3; i++)
{
Console.Write(" Hell " + i);
Monitor.Wait(g1);
Console.Write(" Waitabc " + i);
Monitor.Pulse(g1);
}
Monitor.Exit(g1);
}
};
public class xxx
{
public ggg g1;
public void pqr( )
{
Monitor.Enter(g1);
for ( int i = 1; i <= 3; i++)
{
Console.WriteLine(" Everyone " + i);
Monitor.Pulse(g1);
Monitor.Wait(g1);
Console.Write(" Waitpqr " + i);
}
Monitor.Exit(g1);
}
};
public class zzz
{
public static void Main(String[] args)
{
ggg g = new ggg( );
yyy a = new yyy( );
a.g1 = g;
Thread t = new Thread(new ThreadStart(a.abc));
t.Start( );
xxx b = new xxx();
b.g1 = g;
Thread t1 = new Thread(new ThreadStart(b.pqr));
t1.Start( );
}
};
Output
Hell 1 Everyone 1
Waitabc 1 Hell 2 Waitpqr 1 Everyone 2
Waitabc 2 Hell 3 Waitpqr 2 Everyone 3
cs Waitabc 3 Waitpqr 3
The above example may be a protracted one, yet it is fascinating.
The world has never been able to work with each other. The only global body we have is the UNO. People are mostly loners.
In the entry point function Main, we create an object g, which is an instance of a class ggg, having no code or variable. It
embodies the emptiness of space. This is a class that is incapable of doing any good or bad. We then create two objects
that look like yyy and xxx respectively, and pass them as delegates, so that the threads can call functions abc and pqr. We
also initialize the object g1, an instance of ggg, in each of them to g. This is crucial. The g1's in yyy and xxx represent the
same g that is created in Main.
After initializing the requisite members, we activate the two threads. As earlier, let us assume that the function abc gets
called first.
Monitor.Enter considers taking a handle to any object, which is to be synchronized between multiple instances of threads, as
its first parameter. This function needs an Exit function to release its handle. Thus, the number of Exits in the program must
correspond to the number of Enters.
It prints "Hell", and then due to the Wait function, it waits indefinitely, till it finally receives runtime notification. However, the
thread accomplishes nothing significant. Thus, we do not see the Waitabc displayed, since it is entered after the Wait
function.
The second thread starts executing the function pqr. Monitor.Enter uses the same synchronized object, and now it displays
Everyone. The next function to be called in pqr is Monitor.Pulse. Pulse does a very simple thing. It wakes up any thread
having the same handle, which happens to be waiting at a Wait. Thus, the thread in abc wakes up. However, the one in pqr
waits for someone to Pulse it.
By using Wait and Pulse, we can easily play a game of tag. The thread t performs some work and waits for thread t1 to wrap
up whatever work it is preoccupied with. Thread t does not know how long thread t1 will take to fulfill its side of the bargain.
But no sweat! Thread t waits at a Wait for the thread t1 to Pulse it. Then, thread t1 waits at a Wait for thread t to do some
work. When thread t concludes, it Pulses thread t1, and so on. This can go on and may involve some other threads too.
The threads use the handle g, which is the synchronized region. It is akin to being an integral part of a clandestine social
group. The parameter to these Monitor functions clubs them together as a group. If you change the handle, the group breaks
up, leaving your thread in a lurch. The Wait function can also be made to wait for a specified time period.
If we change the line Monitor.Wait(g1) to Monitor.Wait(g1,0), the output changes dramatically.
A monitor is associated with an object on demand and it cannot be instantiated at all. If the constructor is private, we can
never create an object. But, the static functions of that object can be used. The Monitor functions can be called from
anywhere since they are unbound. There are no restrictions on the sources of the object to be called.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
Monitor.Enter(this);
Monitor.Enter(this);
for ( int i = 1; i<=3;i++)
{
System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " ");
}
Monitor.Exit(this);
}
}
public class zzz
{
public static void Main() {
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Start();
t1.Start();
}
}
Output
1 2
2 2
3 2
The Exit function can be called as often as one desires. In this program, we have two threads, t and t1. Let us assume that
thread t has the first go. At this time, it will pass through the first Monitor.Enter, as well as the second Monitor.Enter, without
waiting at all. However, thread t1 will have to wait at the first Monitor.Enter, since the thread t called the Enter function twice,
but Exited only once. Thus, the program never quits out. Had it called Exit twice, the thread t1 too would have woken up.
a.cs
using System.Threading;
public class yyy {
public int j=1;
public void abc()
{
Monitor.Enter(j);
for ( int i = 1; i<=3;i++)
{
System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " ");
}
Monitor.Exit(j);
}
}
public class zzz
{
public static void Main() {
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
t.Start();
}
}
Output
1 2
2 2
3 2
Unhandled Exception: System.Threading.SynchronizationLockException: Exception of type
System.Threading.SynchronizationLockException was thrown.
at yyy.abc()
Monitor.Enter takes an object, and not a variable, as a parameter. This is the reason why we used this parameter or some
reference object, in the earlier programs. If a variable or a value object is used, an exception will be thrown. Thus, value
types or null objects are not allowed as parameters to Monitor.Enter.
a.cs
using System.Threading;
public class xxx
{
}
public class ttt
{
}
public class yyy
{
static int p = 1;
xxx x = new xxx();
ttt t = new ttt();
public void abc()
{
if ( p == 1)
{
Monitor.Enter(x);
p++;
}
else
Monitor.Enter(t);
for ( int i = 1; i<=3;i++)
{
Thread.Sleep(1000);
System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " ");
}
Monitor.Exit(x);
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Start();
t1.Start();
}
}
Output
1 2
1 3
2 2
2 3
3 2
3 3
The Enter function must be used with some caution. The variable p initially has a value of 1. The first thread t sees the value
of p as 1. Hence, the 'if' statement is true. Thus, it crosses Monitor.Enter with x as a parameter. It then takes a snooze at the
Sleep function, while the second thread t1 executes function abc, where it sees the value of variable p as 2. This thread now
meets the Monitor.Enter function, with t as the parameter. The object reference given to this Enter is entirely at variance with
the object given to the earlier one. Thus, both the threads execute the Enter function, which fails the very objective of the
Enter function. For Enter to work as expected, it should be provided with the same object as a parameter to itself.
The concept of a Lock is normally used to explain the Monitor class. One thread gets a Lock, while the others wait until the
lock is released.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
bool b = Monitor.TryEnter(this);
System.Console.WriteLine(b);
for ( int i = 1; i<=3;i++)
{
Thread.Sleep(1000);
System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " ");
}
Monitor.Exit(this);
}
}
public class zzz
{
public static void Main() {
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Start();
t1.Start();
}
}
Output
True
False
1 2
1 3
2 2
2 3
3 2
3 3
The TryEnter function is similar to the Enter function, but it does not block. If the thread enters successfully, TryEnter returns
a true. This is what happens the first time. But in the case of the second thread t, it returns a false, even when it enters the
critical section.
a.cs
using System.Threading;
public class yyy
{
public void abc()
{
bool b = Monitor.TryEnter(this,1000);
System.Console.WriteLine(b);
for ( int i = 1; i<=3;i++)
{
Thread.Sleep(1000);
System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " ");
}
Monitor.Exit(this);
}
}
public class zzz
{
public static void Main()
{
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Start();
t1.Start();
}
}
Output
True
False
1 2
1 3
2 2
2 3
3 2
3 3
The TryEnter function is overloaded to accept a number as a parameter, which represents the time duration for which the
TryEnter function should block or wait. In our case, the timeout exceeds the time that thread t spends in the function. Hence,
we get a value of False. If we add an extra zero to the time parameter, it will return a true instead. If the value of the
parameter is infinite, the behaviour of the TryEnter becomes akin to that of Enter.
Thread Attributes
a.cs
using System.Threading;
public class yyy
{
[System.ThreadStaticAttribute ()]
public static int j = 1;
public static int k = 1;
public void abc()
{
for ( int i = 1; i<=3;i++)
{
Thread t2 = Thread.CurrentThread;
j++;k++;
System.Console.Write(i + "." + t2.Name + " j=" + j + " k=" + k + " ");
Thread.Sleep(1);
}
}
}
public class zzz
{
public static void Main() {
yyy a = new yyy();
Thread t = new Thread(new ThreadStart(a.abc));
Thread t1 = new Thread(new ThreadStart(a.abc));
t.Name="One";
t1.Name="Two";
t.Start();
t1.Start();
}
}
Output
1.One j=1 k=2 1.Two j=1 k=3 2.One j=2 k=4 2.Two j=2 k=5 3.One j=3 k=6 3.Two j=3 k=7
A static variable is a loner, as reiterated by us on numerous occasions. It belongs to the class and not to an object. Thus,
there will always be a single static variable.
Let us consider a case where we have two threads t and t1 executing code in the same function abc, that also contains
static variables j and k. The first question that strikes us is 'Will each of the threads see the same static variable or a different
one?' Also, if we assume that both threads cater to the same static variable, when one thread increments the variable, will
the other thread see the new value? And if not, then, is the compiler creating a separate static variable for each thread?
Too many questions that need answers!
We want to possess the best of both the worlds. At times, we need the threads to work on the same static variable, while at
other times, we need the threads to access separate copies of the static variable. The default behaviour is that of the static
variable being shared. Thus, the variable k is incremented by both the threads, and each thread sees the same value. The
value of k finally reaches 7 at the end.
The variable j has an attribute ThreadStaticAttribute above it. This attribute may have a fancy name, but it merely creates a
separate variable for each thread executing the function. Thus, we have two static variables j, one for each thread t and t1.
Any changes made to the value of the variable j by t, does not get reflected in the static variable j of the thread t1.
1.One j=2 k=2 1.Two j=3 k=3 2.Two j=4 k=4 2.One j=5 k=5 3.Two j=6 k=6 3.One j=7 k=7
The above attribute only acts on static variables. We see the above output when we remove static from the variables j and k.
The compiler is very clear. The attribute ThreadStaticAttribute is only to be used on static variables, but when applied on
non-static variables, the compiler does not generate any error or warning. It simply ignores the attribute. Thus, instance
variables are shared across threads, whereas, local variables like i are independent of threads. Thus, a variable can either
be shared across threads or may be independent of the thread. No in-between options are allowed.
Events
a.cs
using System.Threading;
public class zzz
{
public static void Main() {
ManualResetEvent a;
a = new ManualResetEvent(false) ;
System.Console.WriteLine("Before WaitOne " );
bool b = a.WaitOne(1000,false);
System.Console.WriteLine("After WaitOne " + b);
}
}
Output
Before WaitOne
After WaitOne False
We have created an object a that is an instance of a ManualResetEvent class. The constructor is assigned a value of false.
Then, we call a function WaitOne from this class with a number as the first parameter, and a boolean value as the second
parameter. This number, 1000, is the number of milliseconds for which we want the thread to wait at the function WaitOne.
The thread therefore waits for one second before quitting out, and then returns a False. Had we used the enum
Timeout.Infinite that has a value of -1, we could have made the function wait forever. Thus, we can keep a thread waiting
either for a specified duration of time or forever.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a;
a = new ManualResetEvent(true) ;
System.Console.WriteLine("Before WaitOne " );
bool b = a.WaitOne(1000,false);
System.Console.WriteLine("After WaitOne " + b);
}
}
Output
Before WaitOne
After WaitOne True
By changing the value in the constructor to true, the thread just refuses to wait for anyone. It just whizzes past, without even
acknowledging the presence of the function WaitOne. Further, the return value of WaitOne i.e. b returns a True.
Let us delve a little deeper into this mystery. A ManualResetEvent is like a boolean variable. It can possess only one of the
two values, true or false. When we first created such an object, we gave it a value of false. So, the function WaitOne waited
till the Event object turned into True or the time value expired. Since the time duration got over while waiting, and the value
of the Event object was not set to True, it stopped blocking and returned with a value of false.
In the next example, the event object already has a value true and hence, there is no wait. Here, the function WaitOne
returns true because the non-blocking in this case, cannot be attributed to a timeout. Thus, a ManualResetEvent has two
states, true or false; or in technical lingo, signaled or non-signaled. A value of true implies a signaled state, while a false
would mean that it is in the non-signaled state.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a;
a = new ManualResetEvent(true) ;
System.Console.WriteLine("Before WaitOne " );
bool b = a.WaitOne(1000,true);
System.Console.WriteLine("After WaitOne " + b);
b = a.WaitOne(10000,true);
System.Console.WriteLine("After second WaitOne " + b);
}
}
Output
Before WaitOne
After WaitOne True
After second WaitOne True
Since we do not consider ourselves to be very cerebral, we shall desist from using fancy terminology like signaled or non-
signaled. Instead, we shall stick to the simple true and false. We initially created the object a to be true or signaled (Oops!
There we go again!). It then passed the first and the second WaitOne without waiting. This occurred because it is a Manual
ResetEvent (as the name itself suggests), and not automatic. Once it is set to true, the event cannot change to false
automatically. This has to be accomplished manually.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a;
a = new ManualResetEvent(true) ;
System.Console.WriteLine("Before WaitOne " );
bool b = a.WaitOne(1000,true);
System.Console.WriteLine("After WaitOne " + b);
a.Reset();
b = a.WaitOne(10000,true);
System.Console.WriteLine("After second WaitOne " + b);
}
}
Output
Before WaitOne
After WaitOne True
After second WaitOne False
The Reset function can be used to change the state from true to false as it changes the state to false. Hence, it has to wait in
queue like a commoner, since the event ignores the earlier WaitOne. After some time, it gets activated due to a timeout and
the function WaitOne returns a False.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a;
a = new ManualResetEvent(false) ;
System.Console.WriteLine("Before WaitOne " );
a.Set();
bool b = a.WaitOne(1000,true);
System.Console.WriteLine("After WaitOne " + b);
b = a.WaitOne(10000,true);
System.Console.WriteLine("After second WaitOne " + b);
}
}
Output
Before WaitOne
After WaitOne True
After second WaitOne True
Now, despite the fact that that the Event is originally false or non-signaled, the Set function sets it to true or the signaled
state. At this stage, no power on earth is equipped to stop the event as it surges past the WaitOnes, treating them with
disdain. It is not in the least concerned about stopping-by to pay homage to them. Such arrogance !
The class ManualResetEvent is a sealed class, like most other classes belonging to the Thread family. The developers at
Microsoft were of the belief that no one would be able to add any more value to the class, and thus forbade any changes.
This class is also derived from another class called WaitHandle, which in fact, embodies functions like WaitOne etc. The
constructor has to be passed a parameter that affirms the initial state of the Event object. No default state is available. The
Set and Reset methods return a boolean value, which indicates whether the change has taken place successfully or
otherwise.
WaitHandle is a class from which ManualResetEvent is derived. A class that offers functions which are polite, is called a
synchronization class. People who are polite, wait for others to finish doing their work, and it is only then that they proceed
with their own work. Any class that waits for another is called a synchronization class. All synchronization objects derive from
WaitHandle, and so does ManualResetEvent.
We are cautioned not to use this class directly, since it is the other classes that use this class. The documentation very
clearly specifies that the CLR i.e. the Common Language Runtime or code written by Microsoft, calls the constructor of
WaitHandle. Therefore, do not use this class directly. You are being forewarned!
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a,b;
a = new ManualResetEvent(false) ;
b = new ManualResetEvent(true) ;
WaitHandle [] w = new WaitHandle[2];
w[0] = a; w[1] = b;
System.Console.WriteLine("Before WaitAll " );
bool c = WaitHandle.WaitAll(w,10000,true);
System.Console.WriteLine("After WaitAll " + c);
}
}
Output
Before WaitAll
After WaitAll False
We can complicate life as much as we like. Similarly, we can complicate the WaitOne, by introducing its elder brother,
WaitAll. This function will wait for all the event objects to become true or signaled, or it will stay there till the timeout occurs.
In this manner, life can be made as complicated as we like. Until all the events reach the signaled state, the WaitAll remains
extremely stubborn and does not budge from its vantage position. It does not take cognizance if a few of the events are
signaled. All the events should be signaled. This could be a number approaching infinity.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a,b;
a = new ManualResetEvent(false) ;
b = new ManualResetEvent(true) ;
WaitHandle [] w = new WaitHandle[2];
w[0] = a; w[1] = b;
System.Console.WriteLine("Before WaitAll " );
bool c = WaitHandle.WaitAll(w);
System.Console.WriteLine("After WaitAll " + c);
}
}
Output
Before WaitAll
The number of functions in the class WaitHandle may be numerous, but most of them are only helper functions, which make
life tranquil. The WaitAll function, if called with a single parameter, assumes that the second parameter is Timeout.Infinite or
-1. These overloads can be ignored safely. It is the same for the WaitOne method.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a,b;
a = new ManualResetEvent(false) ;
b = new ManualResetEvent(true) ;
WaitHandle [] w = new WaitHandle[2];
w[0] = a; w[1] = a;
System.Console.WriteLine("Before WaitAll " );
bool c = WaitHandle.WaitAll(w);
System.Console.WriteLine("After WaitAll " + c);
}
}
Output
Before WaitAll
Unhandled Exception: System.DuplicateWaitObjectException: Exception of type
System.DuplicateWaitObjectException was thrown.
at System.Threading.WaitHandle.WaitMultiple(WaitHandle[] waitHandles, Int32 millisecondsTimeout, Boolean
exitContext, Boolean WaitAll)
at System.Threading.WaitHandle.WaitAll(WaitHandle[] waitHandles, Int32 millisecondsTimeout, Boolean
exitContext)
at System.Threading.WaitHandle.WaitAll(WaitHandle[] waitHandles)
at zzz.Main()
The CLR (Common Language Runtime, if you have forgotten) never sleeps, but the compiler can be caught dozing at times.
C# hates duplicates, and thus, we cannot pass the same handle to the WaitHandle array. If you attempt to do so, a runtime
exception will be thrown even when there was no reason to throw an exception. The runtime could have simply ignored the
duplicate, but it chose not to.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
ManualResetEvent a,b;
a = new ManualResetEvent(false) ;
b = new ManualResetEvent(true) ;
WaitHandle [] w = new WaitHandle[2];
w[0] = b; w[1] = a;
System.Console.WriteLine("Before WaitAll " );
int c = WaitHandle.WaitAny(w);
System.Console.WriteLine("After WaitAll " + c);
}
}
Output
Before WaitAll
After WaitAll 0
Change line containing w[0] = b; w[1] = a; to w[0] = a; w[1] = b; and the output changes to the following:-
Output
Before WaitAll
After WaitAll 1
The WaitAny function waits till any of the events change to signaled or true. When this occurs, it returns the array index of
the event which caused the exit. In this case, object b is in the signaled state, and since it is the first member of the array,
the return value is 0. On interchanging the object to b, which is the second array member, the return value becomes 1. If
both events are in the signaled state, then the lower array index is returned. If a timeout occurs, the value returned is 258.
AutoResetEvent Class
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
AutoResetEvent a;
a = new AutoResetEvent(false) ;
System.Console.WriteLine("Before WaitAll " );
bool c = a.WaitOne(1000,true);
System.Console.WriteLine("After WaitOne " + c);
}
}
Output
Before WaitAll
After WaitOne False
Let us now move up the value chain. The AutoResetEvent class works in the same way like a ManualResetEvent class in
the above example. It simply waits for the timeout to take place or the Event to be signaled.
a.cs
using System.Threading;
public class zzz
{
public static void Main() {
AutoResetEvent a;
a = new AutoResetEvent(true) ;
System.Console.WriteLine("Before WaitAll " );
bool c = a.WaitOne(1000,true);
System.Console.WriteLine("After WaitOne " + c);
c = a.WaitOne(10000,true);
System.Console.WriteLine("After WaitOne1 " + c);
}
}
Output
Before WaitAll
After WaitOne True
After WaitOne1 False
Ah! Again the wait. The AutoResetEvent object safely crosses the first WaitOne. But there is one major variation now in that,
the state of the object changes from true to false or signaled to non-signaled. Thus, it is obliged to pay homage for some
time at the second Wait. The name here is Auto and not Manual. Just as we would change color if we saw a wild boar
charging at us, the AutoResetEvent changes state at the Wait. Everything else remains identical.
Mutexes
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
public static void Main()
{
m = new Mutex(true,"vijay");
zzz a=new zzz( );
Thread t= new Thread(new ThreadStart(a.abc));
t.Start();
}
public void abc( )
{
System.Console.WriteLine("abc start");
m.WaitOne( );
System.Console.WriteLine("abc end");
}
}
Output
abc start
If the boolean value of true in the Mutex constructor is changed to false, the output will change to the following:-
Output
abc start
abc end
A mutex is a synchronization object derived from the class WaitHandle. A Mutex is, in some sense, similar to the other Event
classes.
We commence by creating a mutex and assigning it a boolean value of either true or false. In this context, these values have
a slightly different connotation. They decide whether the creating thread owns the object or not. True allows the thread to
own it, whereas False does not. Thus, with a mutex, we need to become very materialistic and start taking ownership of
things. The current thread owns the mutex while the other threads are inclined to own it.
True or false, signaled or non-signaled, own it or not, are all the same concepts. The main thread already owns the mutex,
which is named as vijay. The name is optional and is used mostly to refer to the mutex. Thereafter, we create a thread which
calls the function abc. After displaying a message, the function WaitOne is called. This function will now stake a claim for
ownership of the mutex, but since the main thread owns it, thread t cannot proceed beyond this function until the original
thread gives up ownership. If we change the True in the constructor to False, then the ownership is not claimed. Thus, the
thread t will not have to wait at the WaitOne as there is no owner.
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
public static void Main()
{
m = new Mutex(true,"vijay");
zzz a=new zzz( );
Thread t= new Thread(new ThreadStart(a.abc));
t.Start();
}
public void abc( )
{
System.Console.WriteLine("abc start");
m.ReleaseMutex();
m.WaitOne( );
System.Console.WriteLine("abc end");
}
}
Output
abc start
Unhandled Exception: System.ApplicationException: Attempt to release mutex not owned by caller.
at System.Threading.Mutex.ReleaseMutexNative(IntPtr handle)
at System.Threading.Mutex.ReleaseMutex()
at zzz.abc()
The main thread becomes the owner of the mutex as the boolean value supplied in the mutex constructor is True. Then, in
the function abc, we try to release the ownership of the mutex by using the function ReleaseMutex. The thread t does not
own the mutex. Hence, we get a runtime error as only the owner i.e. the main thread, can release the ownership of a mutex
and pass it on to another thread.
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
public static void Main() {
m = new Mutex(true,"vijay");
zzz a=new zzz( );
Thread t= new Thread(new ThreadStart(a.abc));
t.Start();
System.Console.WriteLine("Before Thread Sleep");
Thread.Sleep(10000);
System.Console.WriteLine("After Thread Sleep");
m.ReleaseMutex();
System.Console.WriteLine("All over");
}
public void abc( )
{
System.Console.WriteLine("abc start");
m.WaitOne( );
System.Console.WriteLine("abc end");
}
}
Output
Before Thread Sleep
abc start
After Thread Sleep
abc end
All over
Now alls well that ends well. The main thread sleeps for a little while and then calls ReleaseMutex. This awakens the thread
t, and thus, the function abc now quits out. Remember that you cannot give away what you do not own.
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
public static void Main()
{
m = new Mutex(true,"vijay");
zzz a=new zzz( );
Thread t= new Thread(new ThreadStart(a.abc));
t.Start();
System.Console.WriteLine("Before Thread Sleep");
Thread.Sleep(1000);
System.Console.WriteLine("After Thread Sleep");
m.ReleaseMutex();
System.Console.WriteLine("Before WaitOne");
m.WaitOne();
System.Console.WriteLine("All over");
}
public void abc( )
{
System.Console.WriteLine("abc start");
m.WaitOne();
System.Console.WriteLine("abc before sleep");
Thread.Sleep(100000);
System.Console.WriteLine("abc end");
}
}
Output
Before Thread Sleep
abc start
After Thread Sleep
abc before sleep
Before WaitOne
There is a long sleep in the function abc. The mutex is still owned by the thread t, while the main thread is trying to regain its
ownership. It can only gain ownership if the thread t releases the mutex or dies. Thus, until the thread t dies, we will not see
All Over displayed at all. We could have had another sleep in abc and we could have released the mutex before that sleep.
The choice is ours. Thus, a mutex is fully concerned with ownership issues. Either you own a mutex or you do not.
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
static Mutex n;
public static void Main()
{
m = new Mutex(true,"vijay");
n = new Mutex(true);
zzz a=new zzz( );
Thread t= new Thread(new ThreadStart(a.abc));
t.Start();
System.Console.WriteLine("All over");
}
public void abc( )
{
System.Console.WriteLine("abc start");
Mutex [] g = new Mutex[2];
g[0] = m;g[1] = n;
Mutex.WaitAll(g);
System.Console.WriteLine("abc end");
}
}
Output
All over
abc start
The program will hang. This is because we have two mutexses that have to be waited upon. Both m and n fill up the array g,
and since both are true, the function abc will wait forever. Same rules of event classes apply to a mutex object.
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
public static void Main()
{
m = new Mutex(true,"vijay");
zzz a=new zzz( );
Thread t= new Thread(new ThreadStart(a.abc));
t.Start();
System.Console.WriteLine("Before Thread Sleep");
Thread.Sleep(1000);
System.Console.WriteLine("After Thread Sleep");
m.ReleaseMutex();
System.Console.WriteLine("Before WaitOne");
m.WaitOne();
System.Console.WriteLine("All over");
}
public void abc( )
{
System.Console.WriteLine("abc start");
m.WaitOne();
System.Console.WriteLine("abc after Wait");
m.WaitOne();
System.Console.WriteLine("abc after second Wait");
Thread.Sleep(10000);
System.Console.WriteLine("End");
}
}
Output
Before Thread Sleep
abc start
After Thread Sleep
abc after Wait
abc after second Wait
Before WaitOne
End
All over
The same rules about mutex ownership as mentioned earlier are discussed here. There may be two WaitOne functions, but
the first WaitOne that gets the ownership, retains it. Thus, there was no wait between the first and the second wait. The
concept of a mutex is extremely simple. A particular thread owns it. It can cross a wait without waiting and only when it
releases the mutex can another thread claim and possess its ownership. Other threads cannot own it and they will have to
wait at a wait. Dual ownership is not allowed.
a.cs
using System.Threading;
public class zzz
{
static Mutex m;
public static void Main()
{
m = new Mutex(false,"vijay");
zzz a=new zzz( );
System.Console.WriteLine("abc start");
m.WaitOne( );
System.Console.WriteLine("abc end");
}
}
Output
abc start
abc end
A Mutex only works with multiple threads. So, using a mutex with a single thread is futile, because a mutex is concerned
with determining as to which thread owns it. Therefore, there must be at least two threads.
Timers
a.cs
using System.Threading;
public class zzz
{
public static void Main() {
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,100,0);
Thread.Sleep(1000);
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
hell
Timers are time-related. We have created a timer object and have passed it 4 values in its constructor. The first parameter is
the delegate object which represents the function that should be called after a certain interval elapses. The second
parameter is the object to be passed to the timer function. The third and fourth parameters are numbers representing time
i.e. time and period. If the thread is not asked to sleep, the main thread will quit out and there will be no thread running. The
entire program will halt and all the unfired timers will die.
Thus, if we remove the last Sleep, the word 'hell' does not get displayed. The timer delegate has to receive an object as a
parameter since it is part of the delegate signature. The timer also has to wait for a specified time which is stated in the
constructor, before it can call the function. This wait is accomplished using a thread in a thread pool. Needless to say, the
Timer class is a sealed class.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,100,0);
t.Dispose();
Thread.Sleep(1000);
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
(none)
If we ever desire to cancel the timer for whatever reasons, we can call the Dispose method to kill the timer. The timer dies
and the function to be called does not get called at all.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
ManualResetEvent e = new ManualResetEvent(false);
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,10000,300);
t.Dispose(e);
e.WaitOne();
System.Console.WriteLine("All Over");
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
All Over
The Dispose function can also take a parameter which is an event that gets signaled when the timer dies. Thus, the program
that would have waited indefinitely now quits out because, removing the timer from the timer queue instantly signals an
event.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,100,1);
Thread.Sleep(500);
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
hell
hell
hell
hell
and so on
The third parameter to the timer constructor is the duration in milliseconds after which the timer should be fired. The second
number can be either a 0 or any other number. Zero means the timer fires once and any other number signifies it as a
periodic timer. This periodic timer keeps executing the function abc every 100 milliseconds, until told to do otherwise.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,100,1);
Thread.Sleep(115);
t.Change(100,0);
Thread.Sleep(1300);
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
hell
hell
hell
The Change function is used to stop a periodic timer. Thus, the timer can be made to run for some time in a periodic manner
and thereafter, the Change can be used to stop it from executing repeatedly.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,100000,1);
Thread.Sleep(115);
t.Change(100,0);
Thread.Sleep(1300);
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
hell
The timer initially is set to go off after a very long time. We let the main thread sleep for a little while but then change the due
time of the timer to a smaller value. Thus, we can use the Change function to alter the initial settings of the timer.
a.cs
using System.Threading;
public class zzz
{
public static void Main()
{
zzz a = new zzz();
a.pqr();
}
public void pqr()
{
Timer t;
yyy b = new yyy();
t = new Timer(new TimerCallback(b.abc),this,100,300);
Thread.Sleep(1000);
}
}
public class yyy
{
public void abc(object o)
{
System.Console.WriteLine("hell");
}
}
Output
hell
hell
hell
Our dictum has always been to understand things one step at a time. The last parameter to the timer constructor can either
be zero or any other value. If the value is 100, it means that every hundred seconds the timer will go off, until it is stopped by
a Change or a Dispose. Earlier, we had used the number 1 to signify that the timer should be called every 1 second. You are
free to decide these timer values depending upon what you intend to use the timer for. The values cannot be negative and
cannot exceed 4294967294 either. If you do so, an exception will occur. Exceptions, lest you have forgotten, are generated
at runtime only.
Thread Pool
a.cs
using System;
using System.Threading;
public class yyy {
public ManualResetEvent a = new ManualResetEvent(false);
public void abc(Object s)
{
a.WaitOne(10,true);
Console.WriteLine("{0} ", Thread.CurrentThread.GetHashCode());
}
};
public class zzz {
public static void Main() {
ManualResetEvent b = new ManualResetEvent(false);
yyy y = new yyy();
for (int i=1;i<=5;i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(y.abc),1);
}
b.WaitOne(10000,true);
}
}
Output
2
2
2
2
2
The rationale of a thread pool is that the decision makers at Microsoft did not want us to spend time taking care of threads
like mothers take care of babies.
We will first explain the above program and then delve into the nitty-gritty of thread pools. Since we are lazy, we use a for
statement to avoid repeating the same code over and over again. The function QueueUserWorkItem will be called at least
five times because it is placed in this for loop.
QueueUserWorkItem function requires one, or at the most, two parameters. The first parameter, which is the name of a
function, is most crucial. The name is never ever assigned directly, but indirectly, using a WaitCallback object. The function
to be called is y.abc. Hence, it is passed a parameter to WaitCallback. The second parameter to the function
QueueUserWorkItem is the number 1. As a result, the function abc has to accept a parameter of type object which will
contain the value 1. A parameter of type object does not have any useful code and by itself is totally useless.
Every entity in C# is finally derived from the object class. Thus, every entity is of an object type. Whenever we are not aware
of the parameter type to be received in a function, or in cases where we want to receive multiple data types, the data type of
object is used. Object is like a rubber man; it can fit anywhere and everywhere. By giving the function name abc to the
function QueueUserWorkItem, abc will be called five times by a thread. The function waits for a small amount of time at an
event and then uses the function GetHashCode to print the name/id of the thread. This function will print the thread id that is
calling abc.
From our output, we can conclude that only two threads execute the function abc. Commenting the Wait statement will
display the same id for the thread. This means that no new thread executes the function. Thus, instead of two threads, only
a single thread is used. Efficiency, thy name is Thread Pool.
We are thus posting work items to a common place or thread pool. Then, a thread is allocated to execute the work item or
function. The first available thread from the thread pool executes the function. We are only using one thread pool per
program.
There is a lot of overhead in managing threads. A lot of time is spent figuring out which thread is sleeping, i.e. waiting for an
event to occur. Most of the time, threads are in this inert state. At times, threads wake up to check/poll for a change that is
expected to occur, such as a key press, or to update some counter or status information and fall asleep again. Threads are
like bears, they love sleeping.
Thread Pooling is a means of managing threads more efficiently. This is done by providing your application with a pool of
threads that are managed by the system. All threads that do work are called worker threads. There is a thread that monitors
the status of threads waiting at any of the wait functions. When the wait is over, the callback function will be executed.
The next program demonstrates how a function can be called after a specified time duration has elapsed. There is no way to
cancel a function from being executed once it has gone into the thread pool. A prayer will also not help. Timers and Waits
use the thread pool without our knowledge.
The thread pool is created when we call the function QueueUserWorkItem for the first time or when we use a timer function.
The number of threads that form part of a thread pool is limited by the amount of memory available. By today's standards,
this means that more threads can be made available than we would ever need. These threads receive the default stack size
and run at the default priority. No special priority is accorded. For the trivia fans, a thread can handle up to 63 wait
operations. No concept is perfect. Thus, one significant disadvantage of a thread pool is that it involves a long calculation.
a.cs
using System;
using System.Threading;
public class yyy
{
public void abc(object s, bool b)
{
Console.WriteLine("{0} {1}", Thread.CurrentThread.GetHashCode(),b);
}
};
public class zzz
{
public static void Main()
{
ManualResetEvent a = new ManualResetEvent(false);
ManualResetEvent b = new ManualResetEvent(false);
yyy y = new yyy();
ThreadPool.RegisterWaitForSingleObject(a,new WaitOrTimerCallback(y.abc),1,1000,true);
b.WaitOne(10000,true);
}
}
Output
2 True
As mentioned earlier, we would like our function to be called after a certain wait. To accomplish this, we use a function with a
very large name called RegisterWaitForSingleObject. The first parameter is the handle of an event. This has been set to
false or non signaled. The second parameter is a delegate of type WaitOrTimerCallback which is similar to a WaitCallback.
The difference is that the signature of the function given to this function, which is abc, has to have two parameters, viz. an
object and a boolean variable. The third parameter is the object that is to be passed to the function. The second last
parameter is a timer that decides the duration after which the function should be called. Finally, the last parameter decides
whether the function is to be executed only once or every time the timer expires.
As our event object is set to false, the function gets called after 1000 milliseconds. When the timer expires, the function abc
obtains a value of true.
By merely changing one line in the above example, the event can be changed to a signaled state.
ManualResetEvent a = new ManualResetEvent(true);
Output
2 False
The function abc gets called immediately, unlike in the earlier program. Also, there is no wait as the event is true or signaled.
The function abc also knows why it has been called since the bool parameter has a value of false, which was true in the
earlier case. Thus, the function abc can look at the value of its second parameter, which indicates whether the timer has
elapsed or the event has been signaled.
a.cs
using System;
using System.Threading;
public class yyy
{
public void Beta(object s, bool b)
{
Console.WriteLine("{0} {1}", Thread.CurrentThread.GetHashCode(),b);
}
};
public class zzz
{
public static void Main()
{
ManualResetEvent a = new ManualResetEvent(false);
ManualResetEvent b = new ManualResetEvent(false);
yyy y = new yyy();
ThreadPool.RegisterWaitForSingleObject(a,new WaitOrTimerCallback(y.Beta),1,10000,true);
a.Set();
b.WaitOne(10000,true);
}
}
Output
2 False
In this program, initially we set the event to false and then, using the Set function, we set it to true immediately. Thus, the
function gets called instantly. You would remember that the function gets called whenever the event is in a signaled state or
the timer expires. This function first checks whether the wait object is signaled or not. If it is signaled, it executes the
function. If it is not, it waits for the timer to elapse or the wait object to come into the signaled state, whichever occurs first.
Interlocked
a.cs
using System;
using System.Threading;
public class yyy
{
public ManualResetEvent a = new ManualResetEvent(false);
int i = 10;
public void abc(Object s)
{
Interlocked.Increment(ref i);
Console.WriteLine("{0} {1}", Thread.CurrentThread.GetHashCode(),i);
}
};
public class zzz
{
public static void Main() {
ManualResetEvent b = new ManualResetEvent(false);
yyy y = new yyy();
for (int i=1;i<=5;i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(y.abc),1);
}
b.WaitOne(10000,true);
}
}
Output
2 11
2 12
2 13
2 14
2 15
Threads can be dangerous for the unwary. The function abc gets called five times by the same or a different thread.
Consider a case where one thread may be incrementing the line i = i + 1. To do so, it will start by asking what is the value of
i. Let us suppose that it is 10. It then increments the value by 1 to make it 11. It may so happen that just as it is about to read
its value, its time slice may get over and another thread may increment the variable i by 1 to make its value 12.
When the first thread receives its next time slice and checks the value of i, it will see the value as 12 and not 11. Thus, the
variable would have been incremented twice instead of once.
The Interlocked class has a sole purpose in life, i.e. to ensure that the variables are not incremented more than once. In a
sense, it synchronizes access to a variable that is being shared by a number of threads. The operation will either be done in
a single time slice or not done at all. It will not be carried over into another time slice ever. These operations, which are
guaranteed to be finished in a single time slice, are called atomic operations.
a.cs
using System;
using System.Threading;
public class yyy
{
public ManualResetEvent a = new ManualResetEvent(false);
public int i = 10;
public void abc(Object s)
{
i++;
Interlocked.CompareExchange(ref i,100,12);
}
};
public class zzz
{
public static void Main()
{
ManualResetEvent b = new ManualResetEvent(false);
yyy y = new yyy();
for (int i=1;i<=5;i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(y.abc),1);
}
b.WaitOne(1000,true);
Console.WriteLine(y.i);
}
}
Output
103
The function abc gets called five times. If we intend to carry out comparisons, we would face the above dilemma. Thus, we
use a simple function called CompareExchange. This functions checks the value of the first parameter that is passed as a
reference, with the third parameter, which in our case is 12. If it matches the value, the first parameter i.e. i is assigned the
value of the second parameter i.e. 100. All this is done in a single time slice. Thus, whenever variable i becomes 12, its
value shoots up to 100, and as a result, the final answer becomes 103.
Like the Increment, there is a Decrement function also that reduces the value of a variable by one. As an aside, a ref
parameter cannot be replaced by an out parameter. In the same vein, the Exchange function changes the value of two
variables passed to it as ref parameters. This is done in an atomic manner.
2
Internet Classes
Before weaving our way into the Internet, let us investigate a few more fundamentals about the C# programming language,
in order to acquire a superior appreciation of internet programming.
No computer in the world is equipped to recognize the letters of the alphabet on its own. Therefore, an internal
representation has to be used. One such representation is called ASCII, which allots a number falling between 0 to 255, to
each of the letters. Here, each letter is represented by a byte, which is an 8-bit number. For instance, the letter 'A' is
represented by the number 65, while the letter 'a' is represented by the number 97.
However, languages such as Japanese and Chinese are remarkably visual, and require a larger range of numbers to
represent them in totality. In order to accommodate the requirement of these languages, the computer industry came out
with a standard called UNICODE, which can represent every known language in the world in its entirety. But, to accomplish
this, this standard imposes the condition that every character in the language should be represented by a 16-bit number, and
not by an 8-bit number.
a.cs
public class zzz
{
public static void Main()
{
byte i = 65;
System.Console.WriteLine(i);
System.Console.WriteLine((char)i);
i = (byte)'A';
System.Console.WriteLine(i);
}
}
Output
65
A
65
The C# language takes cognizance of the fact that the byte data type represents a number ranging from 0 to 255. Thus, by
default, the WriteLine function displays the number that the byte represents. If we typecast the byte i to a char, the WriteLine
function displays its ASCII equivalent instead. The C# language had to indoctrinate a new data type called 'char', which
could represent a UNICODE character or a number ranging from 0 to 65535, since a byte is too diminutive to be able to
accommodate this range of values. A literal or char 'A' cannot be initialized to a byte, since we cannot equate a smaller 8-bit
data type to a larger 16-bit data type. Therefore, a cast operator has to be used.
a.cs
public class zzz
{
public static void Main()
{
char i = 'A';
System.Console.WriteLine(i);
}
}
Output
A
A variable of char data type cannot be equated to a number. It can only be initialized to a literal. The WriteLine function
prefers to receive the 'char' data type, since it can display the value as a letter of the alphabet. Thus, the 'char' data type is
used to store 16 bit UNICODE characters, while the 'byte' data type is employed to store small numbers. The 'string' data
type is used for a sequence of UNICODE characters.
a.cs
public class zzz
{
public static void Main()
{
byte [] i = new byte[5];
i[0] = 65; i[1] = 66;
System.Console.WriteLine(i);
char [] j = new char[5];
j[0] = 'A'; j[1] = 'B';
System.Console.WriteLine(j);
}
}
Output
System.Byte[]
AB
Dealing with an array of bytes is not as straightforward and uncomplicated as dealing with an array of chars. In case of an
array of bytes, the WriteLine function merely displays the data type of the array, whereas, in the case of an array of chars, it
displays the entire array. Thus, we need a technique, by means of which, we are able to display the bytes present in the
form of an array of bytes, using the WriteLine function.
a.cs
public class zzz
{
public static void Main()
{
byte [] i = new byte[5];
i[0] = 65; i[1] = 66; i[2] = 67;i[3] = 68;
string s = System.Text.Encoding.ASCII.GetString(i, 1, 2);
System.Console.WriteLine(s);
}
}
Output
BC
The namespace System.Text.Encoding has a class called ASCII, which contains a static function GetString. This function
accepts three parameters:
• The array of bytes, which is to be converted into a string.
• The starting point in the array ( in our case, 1) refers to the second element in the Array, which is the letter 'B'.
• The number of characters or the length of the string. We have specified it as 2. Hence, only 2 characters are seen.
The function returns a string, which is displayed by employing the WriteLine function.
This methodology thereby, assists in converting a certain number of bytes from a byte array into a string, which can then be
effortlessly printed by the WriteLine function.
The rationale for introducing this function in this chapter is due to the existence of a large number of functions that return
data as an array of bytes. The approach demonstrated above may be employed, to display such data in all such cases.
a.cs
public class zzz
{
public static void Main()
{
string s1 = "vmukhi";
byte[] i;
char [] j = s1.ToCharArray();
i = System.Text.Encoding.ASCII.GetBytes(j);
string s = System.Text.Encoding.ASCII.GetString(i, 0, 5);
System.Console.WriteLine(s);
}
}
Output
vmukh
We now need to resolve another quandary. In the internet-related classes, functions read and write data in the form of an
array of bytes.
We are comfortable dealing with strings, as they are the most natural data type available for representing data. However,
this data type has to be converted into an array of bytes, if it has to be transmitted. But, there is no direct mechanism of
attaining this conversion. The only possibility is to write our own function.
The string is first converted into an array of chars, using ToCharArray method in the string class. As of now, there exists no
magic formula in the string class, which can directly provide an array of bytes. So, we are compelled to utilize the GetBytes
function from the ASCII class, which accepts a character array and converts it into an array of bytes. This is an additional
step that needs to be executed in the conversion process.
The last two lines of the above program merely verify whether all data has been supplied correctly or otherwise.
a.cs
public class zzz
{
public static void Main()
{
byte [] a;
a= abc("ABC");
string s = System.Text.Encoding.ASCII.GetString(a, 0, 3);
System.Console.WriteLine(s);
}
public static byte [] abc( string a)
{
byte [] b = new byte[a.Length];
System.Console.WriteLine(a.Length);
for ( int i = 0 ; i < a.Length ; i++)
{
System.Console.WriteLine(a[i]);
b[i] = (byte)a[i];
}
return b;
}
}
Output
3
A
B
C
ABC
In this program, we write our own function that accepts a string as a parameter, and returns an array of bytes. This function
eliminates the intermediate step of converting the string into an array of chars, prior to its final conversion into an array of
bytes.
The Length member in the string returns the length of the string, and also determines the size of the byte array, which is to
be created. In the 'for' loop, every individual character can be accessed, one at a time, by using the indexer property of the
string class. Concurrently, the byte array is also filled up. The need for a cast operator has been explained earlier. Finally, at
the end of the function, we return this freshly filled up array, and thereafter, display the byte array. The array is displayed
merely to corroborate that all actions have been executed as planned.
File Handling
a.cs
using System;
using System.IO;
class zzz
{
public static void Main()
{
FileStream f = new FileStream("c:z.txt", FileMode.Open, FileAccess.Read);
byte [] a;
a = new byte[512];
int b = f.Read(a, 0, 512);
Console.WriteLine(b);
string s = System.Text.Encoding.ASCII.GetString(a, 0, b);
Console.Write(s);
}
}
z.txt
vijay
mukhi
Output
12
vijay
mukhi
We start by creating an object f, which is an instance of class FileStream. The function is assigned the name of the file that
we want to work with, along with the mode in which it is to be opened. The two parameters, FileMode.Open and
FileAccess.Read, are enums, which open a file for reading.
The Read function in the file stream reads the file. The function has 3 parameters:
• The first parameter is a byte array. The data from the file is to be read into this array.
• The second parameter is the offset position.
• The third parameter is the maximum number of bytes to be read.
Thus, the Read function shall attempt to read upto 512 bytes from the file, until it reaches the end of the file. Since the file
contains only the words 'vijay mukhi', the output is 12, which represents the number of bytes read. This is followed by the
data, i.e. vijay mukhi.
Let us now browse through the data sent by a web server.
a.cs
using System;
using System.Net;
using System.IO;
class zzz
{
public static void Main()
{
WebRequest r = WebRequest.Create("http://www.vijaymukhi.com");
WebResponse re = r.GetResponse();
Stream s = re.GetResponseStream();
Byte[] a = new Byte[51200];
int b = s.Read(a, 0, 51200);
Console.WriteLine(b);
Console.Write(System.Text.Encoding.ASCII.GetString(a, 0, b));
}
}
Output
1085
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN"
"http://www.w3.org/TR/REC-html40/frame.dtd">
<html>
<head>
<title>Vijay Mukhi's Technology cornucopia</title>
</head>
<frameset frameborder="0" framespacing="0" border="0" cols="*" rows="97,*">
<frame marginwidth="0" marginheight="0" src="heading.html" name="heading" noresize scrolling="no">
<frameset frameborder="0" framespacing="0" border="0" cols="210,*" rows="*">
<frameset frameborder="1" framespacing="0" border="0" cols="*" rows="0,*">
<frame marginwidth="0" marginheight="0" src="code.html" name="code" noresize scrolling="no"
frameborder="0">
<frame marginwidth="5" marginheight="5" src="menu_empty.html" name="menu" noresize scrolling="auto"
frameborder="0">
</frameset>
<frame marginwidth="5" marginheight="5" src="main.html" name="text" noresize>
</frameset>
<noframes>
<p>The <code>NOFRAMES</code> element is to be used to give useful content to people with browsers that
cannot display frames. One example is Lynx, a text-based browser.</p>
</noframes>
</frameset>
</html>
We expect you to either have a web server installed on your machine, or at least be connected to the net.
Every machine on the internet is recognized by a name. For example. the Microsoft site is known as www.microsoft.com; the
Java site on the net is known as www.javasoft.com; and my site is known as www.vijaymukhi.com. However, every machine
is also known by the common name of 'localhost'. When the address specified in the browser is www.microsoft.com, the web
server of that machine sends across an HTML file to the browser. The file that is sent across is either named index.html or
default.html.
In the above program, we would like to simulate the functioning of a browser, i.e. we want to fetch an HTML file from a web
server.
In the System.Net namespace, there is a class called WebRequest that has a static function called Create. This function
requires the name of the machine that runs a web server. While reading this book, in case you are not connected to the
Internet, you may use 'http://localhost/' as the name of the machine. Or else, you may connect to a site on the net such as
www.vijaymukhi.com.
A WebRequest object r is returned by the Create function. The WebRequest class has another function called
GetResponse, which returns a WebResponse object. The value returned is stored in a variable called re. Calling the method
GetResponseStream from the WebResponse object returns a Stream object that can be utilized to read the HTML file sent
across by the web server.
The file handling concepts, learnt a short while ago, may be applied here too. The interaction between our program and the
web server is handled by two classes, i.e. WebRequest and WebResponse. We have no inkling as to what each class
accomplishes.
In order to read the HTML file off the Stream object, we create a byte array having a size of 51200. Thereafter, we employ
the Read function to read 51200 bytes, from the inception of the stream, into the array. The value returned by the Read
function is indicative of the number of bytes that have been read off the stream. On displaying this value, the number
obtained is less then 51200 (in our case it is 1085), and not 51200. Therefore, despite our having commanded the Read
function to read upto 51200 bytes, it read only 1085 bytes. This is because it encountered an End Of File mark after having
read 1085 bytes.
In case of an error, the WebResponse object displays a Status code. Few of the values that may be assigned to this Status
code, are as follows:
• 200 indicates 'success'.
• 403 indicates 'permission denied'.
• 404 indicates that the 'file name does not exist'.
Since no errors are visible in our case, we assume the status code to be 200.
Thereafter, the byte array is converted into a string, so that it can be displayed using the GetString function. Therefore, we
see the first 1085 bytes of the HTML file, sent by the web server.
a.cs
using System;
using System.Net;
using System.IO;
class zzz
{
public static void Main()
{
WebRequest r = WebRequest.Create("http://www.yahoo.com");
WebResponse re = r.GetResponse();
Stream s = re.GetResponseStream();
Byte[] a = new Byte[51200];
int b = s.Read(a, 0, 51200);
while (b > 0)
{
Console.Write(System.Text.Encoding.ASCII.GetString(a, 0, b));
b = s.Read(a, 0, 512);
System.Console.WriteLine(b);
}
}
}
We are not in a position to estimate the file size of the HTML file, which has been sent by the web server. So, we take
recourse to the 'while' loop in situations of incertitude or perplexity.
The Read function returns a zero, when there is no more data to be read from the stream. Thus, the 'while' loop terminates
when the value of b becomes zero. Therefore, the last line of the output would always display a zero. In fact, we can
regulate the number of bytes that we want the Read function to read off the stream. Here, we specify a value of 512. The
framework enjoys the license to ignore this number.
In order to retrieve a specific file off the web server, such as a.html, we add the name of the file at the end of the URL. If the
file appertains to the local hard disk, the Create function will be written as follows:
WebRequest r = WebRequest.Create("http://localhost/a.html");
The next query which is likely to vex our minds is: Where would the file a.html be stored on the hard disk? The answer to this
depends upon the web server installed on the machine. In case of IIS or PWS from Microsoft, the file a.html would be placed
in the sub-directory c:inetpubwwwroot. Reading a file sent by a web server is similar to reading a file from the local disk.
Therefore, we do not have to discover two separate ways of reading the same thing.
a.cs
using System;
using System.Net;
using System.IO;
class zzz
{
public static void Main()
{
Uri u = new Uri("http://www.yahoo.com");
HttpWebRequest wr = (HttpWebRequest) WebRequest.Create(u);
AsyncCallback a = new AsyncCallback(abc);
IAsyncResult r = (IAsyncResult) wr.BeginGetResponse(a,wr);
Console.ReadLine();
}
static void abc(IAsyncResult ar)
{
HttpWebRequest r = (HttpWebRequest) ar.AsyncState;
HttpWebResponse re = (HttpWebResponse) r.EndGetResponse(ar);
Stream s = re.GetResponseStream();
Console.WriteLine("Status code: " + re.StatusCode);
Byte[] a = new Byte[51200];
int b = s.Read(a, 0, 51200);
while (b > 0)
{
Console.Write(System.Text.Encoding.ASCII.GetString(a, 0, b));
b = s.Read(a, 0, 512);
System.Console.WriteLine(b);
}
}
}
The above program displays the same output as before, but with a difference. It follows a dissimilar method of writing code.
In the previous example, the Read function waited till the data was received from the Internet. When we are connected to
the Internet, this wait could be indefinite. This effectively would disable the program from proceeding any further. While
awaiting data, the program cannot carry out any other activity. Thus, to avoid squandering of time and resources, we need a
mechanism, by means of which, the program can be intimated about the receipt of data for the HTML file.
The static function Create, now accepts a URI as a parameter. To create this URI object, we pass the same URI string as a
parameter to the constructor. The return value of this function is stored in a HttpWebRequest object, since this class is
derived from the class WebRequest. This class has a function BeginGetResponse, which accepts two parameters.
The first is an AsyncCallback delegate, which requires the name of a function. In the C# world, a delegate simply stands-in
for a function to be called.
The second parameter is a State object. Despite our not making any use of any state related information, we are not allowed
to supply a null value. It is mandatory to supply a value, without which, an error is generated. Thus, we specify the object wr,
of type HttpWebRequest, as the parameter. Under normal circumstances, we are required to create a State object and
furnish it as a parameter.
After a certain time duration, data arrives from the web server, and the function abc gets called. This function is passed
IAsyncResult as a parameter, which has a property AsyncState. Since this is an Object, we cast it to HttpWebRequest.
We require an HttpWebResponse object, in order to obtain a Stream object, which will be employed to read the file received
from the web server. The HttpWebRequest class has a EndGetResponse function, which accepts an IAsyncResult as a
parameter, and returns a HttpWebResponse object. This object, in turn, is derived from the HttpResponse class. This
function terminates the asynchronous request. The remaining code is similar to the above program. We however, are at
liberty to execute other tasks, while the file is being received. Normally, a separate thread runs the function abc in an
asynchronous manner.
a.cs
using System;
using System.Net;
using System.IO;
class zzz
{
public static void Main()
{
Uri u = new Uri("http://www.yahoo.com");
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes
C#   classes

More Related Content

What's hot

Intro To C++ - Class 2 - An Introduction To C++
Intro To C++ - Class 2 - An Introduction To C++Intro To C++ - Class 2 - An Introduction To C++
Intro To C++ - Class 2 - An Introduction To C++
Blue Elephant Consulting
 
Creating Intelligent Chatbots
Creating Intelligent ChatbotsCreating Intelligent Chatbots
Creating Intelligent Chatbots
Kevin Leung
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVM
Bernhard Huemer
 
java
javajava
Java interview question
Java interview questionJava interview question
Java interview question
varatharajanrajeswar
 
Introduction of java
Introduction  of javaIntroduction  of java
Introduction of java
Madishetty Prathibha
 
Java design pattern tutorial
Java design pattern tutorialJava design pattern tutorial
Java design pattern tutorial
Ashoka Vanjare
 
Oop question-bank
Oop question-bankOop question-bank
Oop question-bank
NITIN BHOPALE
 
Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007
Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007
Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007
Arun Kumar
 
C#/.NET Little Wonders
C#/.NET Little WondersC#/.NET Little Wonders
C#/.NET Little Wonders
BlackRabbitCoder
 
L5 m256 block2_unit5
L5 m256 block2_unit5L5 m256 block2_unit5
L5 m256 block2_unit5
Dr Omar M.S Hamed
 
Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...
Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...
Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...
Codemotion
 

What's hot (12)

Intro To C++ - Class 2 - An Introduction To C++
Intro To C++ - Class 2 - An Introduction To C++Intro To C++ - Class 2 - An Introduction To C++
Intro To C++ - Class 2 - An Introduction To C++
 
Creating Intelligent Chatbots
Creating Intelligent ChatbotsCreating Intelligent Chatbots
Creating Intelligent Chatbots
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVM
 
java
javajava
java
 
Java interview question
Java interview questionJava interview question
Java interview question
 
Introduction of java
Introduction  of javaIntroduction  of java
Introduction of java
 
Java design pattern tutorial
Java design pattern tutorialJava design pattern tutorial
Java design pattern tutorial
 
Oop question-bank
Oop question-bankOop question-bank
Oop question-bank
 
Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007
Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007
Lulu.com.java.j2 ee.job.interview.companion.2nd.edition.apr.2007
 
C#/.NET Little Wonders
C#/.NET Little WondersC#/.NET Little Wonders
C#/.NET Little Wonders
 
L5 m256 block2_unit5
L5 m256 block2_unit5L5 m256 block2_unit5
L5 m256 block2_unit5
 
Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...
Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...
Beyond JavaScript Frameworks: Writing Reliable Web Apps With Elm - Erik Wende...
 

Viewers also liked

Perl
PerlPerl
Perl
Tiago
 
Desarrollo+
Desarrollo+Desarrollo+
Desarrollo+
viviangv11
 
Express Scripts_Certificate
Express Scripts_CertificateExpress Scripts_Certificate
Express Scripts_Certificate
Shaqula Taylor
 
New Directions.PDF
New Directions.PDFNew Directions.PDF
New Directions.PDF
Laura Doyle
 
Filestream sistema arquivos
Filestream  sistema arquivosFilestream  sistema arquivos
Filestream sistema arquivos
Tiago
 
國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書
國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書
國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書
昱晴 尤
 
Curso linux professor rafael
Curso linux professor rafaelCurso linux professor rafael
Curso linux professor rafael
Tiago
 
Lpi 101
Lpi 101Lpi 101
Lpi 101
Tiago
 
Printable 04 Dial Machine
Printable 04 Dial MachinePrintable 04 Dial Machine
Printable 04 Dial Machine
gherrington
 
19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?
19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?
19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?Chui-Wen Chiu
 
La historia en diversos tiempos y lugares
La historia en diversos tiempos y lugaresLa historia en diversos tiempos y lugares
La historia en diversos tiempos y lugares
monitatorresgutierrez
 
創意影片製作計畫書+個人的心得
 創意影片製作計畫書+個人的心得 創意影片製作計畫書+個人的心得
創意影片製作計畫書+個人的心得
昱晴 尤
 
Funcionamento do setup
Funcionamento do setupFuncionamento do setup
Funcionamento do setup
Tiago
 
Pascal
PascalPascal
Pascal
Tiago
 
Health Safety Environment (HSE) Plan
Health Safety Environment (HSE) PlanHealth Safety Environment (HSE) Plan
Health Safety Environment (HSE) Plan
ROBERTO BATAHOY GAMALE JR
 

Viewers also liked (15)

Perl
PerlPerl
Perl
 
Desarrollo+
Desarrollo+Desarrollo+
Desarrollo+
 
Express Scripts_Certificate
Express Scripts_CertificateExpress Scripts_Certificate
Express Scripts_Certificate
 
New Directions.PDF
New Directions.PDFNew Directions.PDF
New Directions.PDF
 
Filestream sistema arquivos
Filestream  sistema arquivosFilestream  sistema arquivos
Filestream sistema arquivos
 
國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書
國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書
國立新港藝術高中學生【讓愛茁壯為公益發聲影片製作】計劃書
 
Curso linux professor rafael
Curso linux professor rafaelCurso linux professor rafael
Curso linux professor rafael
 
Lpi 101
Lpi 101Lpi 101
Lpi 101
 
Printable 04 Dial Machine
Printable 04 Dial MachinePrintable 04 Dial Machine
Printable 04 Dial Machine
 
19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?
19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?
19.電腦若遇到停電或斷電,當恢復供電時如何使系統自動開啟?
 
La historia en diversos tiempos y lugares
La historia en diversos tiempos y lugaresLa historia en diversos tiempos y lugares
La historia en diversos tiempos y lugares
 
創意影片製作計畫書+個人的心得
 創意影片製作計畫書+個人的心得 創意影片製作計畫書+個人的心得
創意影片製作計畫書+個人的心得
 
Funcionamento do setup
Funcionamento do setupFuncionamento do setup
Funcionamento do setup
 
Pascal
PascalPascal
Pascal
 
Health Safety Environment (HSE) Plan
Health Safety Environment (HSE) PlanHealth Safety Environment (HSE) Plan
Health Safety Environment (HSE) Plan
 

Similar to C# classes

Designing A Project Using Java Programming
Designing A Project Using Java ProgrammingDesigning A Project Using Java Programming
Designing A Project Using Java Programming
Katy Allen
 
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Bill Buchan
 
Ad507
Ad507Ad507
Ob Essay
Ob EssayOb Essay
Ob Essay
Amanda Burkett
 
Oopp Lab Work
Oopp Lab WorkOopp Lab Work
Oopp Lab Work
Heather Dionne
 
Java Programming
Java ProgrammingJava Programming
Java Programming
Tracy Clark
 
Java Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage EssayJava Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage Essay
Liz Sims
 
Introjs10.5.17SD
Introjs10.5.17SDIntrojs10.5.17SD
Introjs10.5.17SD
Thinkful
 
.Net framework
.Net framework.Net framework
.Net framework
Raghu nath
 
Introduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning SimpleIntroduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning Simple
Sandeep Hijam
 
Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...
Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...
Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...
NicheTech Com. Solutions Pvt. Ltd.
 
A Hand Book of Visual Basic 6.0.pdf.pdf
A Hand Book of Visual Basic 6.0.pdf.pdfA Hand Book of Visual Basic 6.0.pdf.pdf
A Hand Book of Visual Basic 6.0.pdf.pdf
Ann Wera
 
.Net framework by naveen kumar veligeti
.Net framework by naveen kumar veligeti.Net framework by naveen kumar veligeti
.Net framework by naveen kumar veligeti
Naveen Kumar Veligeti
 
Dot Net Fundamentals
Dot Net FundamentalsDot Net Fundamentals
Dot Net Fundamentals
LiquidHub
 
Part i
Part iPart i
Distributed Computing
Distributed ComputingDistributed Computing
Distributed Computing
adil raja
 
Intro to C++ - Class 2 - Objects & Classes
Intro to C++ - Class 2 - Objects & ClassesIntro to C++ - Class 2 - Objects & Classes
Intro to C++ - Class 2 - Objects & Classes
Blue Elephant Consulting
 
Bt0082 visual basic
Bt0082   visual basicBt0082   visual basic
Bt0082 visual basic
smumbahelp
 
Developing Actors in Azure with .net
Developing Actors in Azure with .netDeveloping Actors in Azure with .net
Developing Actors in Azure with .net
Marco Parenzan
 
Nt1310 Unit 3 Language Analysis
Nt1310 Unit 3 Language AnalysisNt1310 Unit 3 Language Analysis
Nt1310 Unit 3 Language Analysis
Nicole Gomez
 

Similar to C# classes (20)

Designing A Project Using Java Programming
Designing A Project Using Java ProgrammingDesigning A Project Using Java Programming
Designing A Project Using Java Programming
 
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
Lotusphere 2007 AD507 Leveraging the Power of Object Oriented Programming in ...
 
Ad507
Ad507Ad507
Ad507
 
Ob Essay
Ob EssayOb Essay
Ob Essay
 
Oopp Lab Work
Oopp Lab WorkOopp Lab Work
Oopp Lab Work
 
Java Programming
Java ProgrammingJava Programming
Java Programming
 
Java Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage EssayJava Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage Essay
 
Introjs10.5.17SD
Introjs10.5.17SDIntrojs10.5.17SD
Introjs10.5.17SD
 
.Net framework
.Net framework.Net framework
.Net framework
 
Introduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning SimpleIntroduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning Simple
 
Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...
Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...
Objective of c in IOS , iOS Live Project Training Ahmedabad, MCA Live Project...
 
A Hand Book of Visual Basic 6.0.pdf.pdf
A Hand Book of Visual Basic 6.0.pdf.pdfA Hand Book of Visual Basic 6.0.pdf.pdf
A Hand Book of Visual Basic 6.0.pdf.pdf
 
.Net framework by naveen kumar veligeti
.Net framework by naveen kumar veligeti.Net framework by naveen kumar veligeti
.Net framework by naveen kumar veligeti
 
Dot Net Fundamentals
Dot Net FundamentalsDot Net Fundamentals
Dot Net Fundamentals
 
Part i
Part iPart i
Part i
 
Distributed Computing
Distributed ComputingDistributed Computing
Distributed Computing
 
Intro to C++ - Class 2 - Objects & Classes
Intro to C++ - Class 2 - Objects & ClassesIntro to C++ - Class 2 - Objects & Classes
Intro to C++ - Class 2 - Objects & Classes
 
Bt0082 visual basic
Bt0082   visual basicBt0082   visual basic
Bt0082 visual basic
 
Developing Actors in Azure with .net
Developing Actors in Azure with .netDeveloping Actors in Azure with .net
Developing Actors in Azure with .net
 
Nt1310 Unit 3 Language Analysis
Nt1310 Unit 3 Language AnalysisNt1310 Unit 3 Language Analysis
Nt1310 Unit 3 Language Analysis
 

More from Tiago

Programacao php moodle
Programacao php moodleProgramacao php moodle
Programacao php moodle
Tiago
 
Apostila cdtc dotproject
Apostila cdtc dotprojectApostila cdtc dotproject
Apostila cdtc dotproject
Tiago
 
6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal
Tiago
 
Guia rapido de_pascal
Guia rapido de_pascalGuia rapido de_pascal
Guia rapido de_pascal
Tiago
 
Python bge
Python bgePython bge
Python bge
Tiago
 
Curso python
Curso pythonCurso python
Curso python
Tiago
 
Curso python
Curso pythonCurso python
Curso python
Tiago
 
Aula 01 python
Aula 01 pythonAula 01 python
Aula 01 python
Tiago
 
Threading in c_sharp
Threading in c_sharpThreading in c_sharp
Threading in c_sharp
Tiago
 
Retirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharpRetirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharp
Tiago
 
Remover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharpRemover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharp
Tiago
 
Obter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharpObter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharp
Tiago
 
Metodo using no_c_sharp
Metodo using no_c_sharpMetodo using no_c_sharp
Metodo using no_c_sharp
Tiago
 
Introdução ao c# para iniciantes
Introdução ao c# para iniciantesIntrodução ao c# para iniciantes
Introdução ao c# para iniciantes
Tiago
 
Interfaces windows em c sharp
Interfaces windows em c sharpInterfaces windows em c sharp
Interfaces windows em c sharp
Tiago
 
Curso de shell
Curso de shellCurso de shell
Curso de shell
Tiago
 
Controle lpt em_c_sharp
Controle lpt em_c_sharpControle lpt em_c_sharp
Controle lpt em_c_sharp
Tiago
 
Classes csharp
Classes csharpClasses csharp
Classes csharp
Tiago
 
C# o basico
C#   o basicoC#   o basico
C# o basico
Tiago
 
Csharp ebook
Csharp ebookCsharp ebook
Csharp ebook
Tiago
 

More from Tiago (20)

Programacao php moodle
Programacao php moodleProgramacao php moodle
Programacao php moodle
 
Apostila cdtc dotproject
Apostila cdtc dotprojectApostila cdtc dotproject
Apostila cdtc dotproject
 
6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal6572501 ldp-apostila-de-turbo-pascal
6572501 ldp-apostila-de-turbo-pascal
 
Guia rapido de_pascal
Guia rapido de_pascalGuia rapido de_pascal
Guia rapido de_pascal
 
Python bge
Python bgePython bge
Python bge
 
Curso python
Curso pythonCurso python
Curso python
 
Curso python
Curso pythonCurso python
Curso python
 
Aula 01 python
Aula 01 pythonAula 01 python
Aula 01 python
 
Threading in c_sharp
Threading in c_sharpThreading in c_sharp
Threading in c_sharp
 
Retirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharpRetirar acentos de_determinado_texto_em_c_sharp
Retirar acentos de_determinado_texto_em_c_sharp
 
Remover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharpRemover caracteres especiais_texto_em_c_sharp
Remover caracteres especiais_texto_em_c_sharp
 
Obter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharpObter ip da_internet_em_c_sharp
Obter ip da_internet_em_c_sharp
 
Metodo using no_c_sharp
Metodo using no_c_sharpMetodo using no_c_sharp
Metodo using no_c_sharp
 
Introdução ao c# para iniciantes
Introdução ao c# para iniciantesIntrodução ao c# para iniciantes
Introdução ao c# para iniciantes
 
Interfaces windows em c sharp
Interfaces windows em c sharpInterfaces windows em c sharp
Interfaces windows em c sharp
 
Curso de shell
Curso de shellCurso de shell
Curso de shell
 
Controle lpt em_c_sharp
Controle lpt em_c_sharpControle lpt em_c_sharp
Controle lpt em_c_sharp
 
Classes csharp
Classes csharpClasses csharp
Classes csharp
 
C# o basico
C#   o basicoC#   o basico
C# o basico
 
Csharp ebook
Csharp ebookCsharp ebook
Csharp ebook
 

Recently uploaded

How to Setup Warehouse & Location in Odoo 17 Inventory
How to Setup Warehouse & Location in Odoo 17 InventoryHow to Setup Warehouse & Location in Odoo 17 Inventory
How to Setup Warehouse & Location in Odoo 17 Inventory
Celine George
 
C1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptx
C1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptxC1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptx
C1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptx
mulvey2
 
Walmart Business+ and Spark Good for Nonprofits.pdf
Walmart Business+ and Spark Good for Nonprofits.pdfWalmart Business+ and Spark Good for Nonprofits.pdf
Walmart Business+ and Spark Good for Nonprofits.pdf
TechSoup
 
writing about opinions about Australia the movie
writing about opinions about Australia the moviewriting about opinions about Australia the movie
writing about opinions about Australia the movie
Nicholas Montgomery
 
IGCSE Biology Chapter 14- Reproduction in Plants.pdf
IGCSE Biology Chapter 14- Reproduction in Plants.pdfIGCSE Biology Chapter 14- Reproduction in Plants.pdf
IGCSE Biology Chapter 14- Reproduction in Plants.pdf
Amin Marwan
 
UGC NET Exam Paper 1- Unit 1:Teaching Aptitude
UGC NET Exam Paper 1- Unit 1:Teaching AptitudeUGC NET Exam Paper 1- Unit 1:Teaching Aptitude
UGC NET Exam Paper 1- Unit 1:Teaching Aptitude
S. Raj Kumar
 
Présentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptx
Présentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptxPrésentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptx
Présentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptx
siemaillard
 
Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...
Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...
Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...
Leena Ghag-Sakpal
 
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem studentsRHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
Himanshu Rai
 
math operations ued in python and all used
math operations ued in python and all usedmath operations ued in python and all used
math operations ued in python and all used
ssuser13ffe4
 
How to Create a More Engaging and Human Online Learning Experience
How to Create a More Engaging and Human Online Learning Experience How to Create a More Engaging and Human Online Learning Experience
How to Create a More Engaging and Human Online Learning Experience
Wahiba Chair Training & Consulting
 
Your Skill Boost Masterclass: Strategies for Effective Upskilling
Your Skill Boost Masterclass: Strategies for Effective UpskillingYour Skill Boost Masterclass: Strategies for Effective Upskilling
Your Skill Boost Masterclass: Strategies for Effective Upskilling
Excellence Foundation for South Sudan
 
clinical examination of hip joint (1).pdf
clinical examination of hip joint (1).pdfclinical examination of hip joint (1).pdf
clinical examination of hip joint (1).pdf
Priyankaranawat4
 
Temple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation resultsTemple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation results
Krassimira Luka
 
Beyond Degrees - Empowering the Workforce in the Context of Skills-First.pptx
Beyond Degrees - Empowering the Workforce in the Context of Skills-First.pptxBeyond Degrees - Empowering the Workforce in the Context of Skills-First.pptx
Beyond Degrees - Empowering the Workforce in the Context of Skills-First.pptx
EduSkills OECD
 
BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...
BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...
BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...
Nguyen Thanh Tu Collection
 
Leveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit InnovationLeveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit Innovation
TechSoup
 
BBR 2024 Summer Sessions Interview Training
BBR  2024 Summer Sessions Interview TrainingBBR  2024 Summer Sessions Interview Training
BBR 2024 Summer Sessions Interview Training
Katrina Pritchard
 
B. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdfB. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdf
BoudhayanBhattachari
 
MARY JANE WILSON, A “BOA MÃE” .
MARY JANE WILSON, A “BOA MÃE”           .MARY JANE WILSON, A “BOA MÃE”           .
MARY JANE WILSON, A “BOA MÃE” .
Colégio Santa Teresinha
 

Recently uploaded (20)

How to Setup Warehouse & Location in Odoo 17 Inventory
How to Setup Warehouse & Location in Odoo 17 InventoryHow to Setup Warehouse & Location in Odoo 17 Inventory
How to Setup Warehouse & Location in Odoo 17 Inventory
 
C1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptx
C1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptxC1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptx
C1 Rubenstein AP HuG xxxxxxxxxxxxxx.pptx
 
Walmart Business+ and Spark Good for Nonprofits.pdf
Walmart Business+ and Spark Good for Nonprofits.pdfWalmart Business+ and Spark Good for Nonprofits.pdf
Walmart Business+ and Spark Good for Nonprofits.pdf
 
writing about opinions about Australia the movie
writing about opinions about Australia the moviewriting about opinions about Australia the movie
writing about opinions about Australia the movie
 
IGCSE Biology Chapter 14- Reproduction in Plants.pdf
IGCSE Biology Chapter 14- Reproduction in Plants.pdfIGCSE Biology Chapter 14- Reproduction in Plants.pdf
IGCSE Biology Chapter 14- Reproduction in Plants.pdf
 
UGC NET Exam Paper 1- Unit 1:Teaching Aptitude
UGC NET Exam Paper 1- Unit 1:Teaching AptitudeUGC NET Exam Paper 1- Unit 1:Teaching Aptitude
UGC NET Exam Paper 1- Unit 1:Teaching Aptitude
 
Présentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptx
Présentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptxPrésentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptx
Présentationvvvvvvvvvvvvvvvvvvvvvvvvvvvv2.pptx
 
Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...
Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...
Bed Making ( Introduction, Purpose, Types, Articles, Scientific principles, N...
 
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem studentsRHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
RHEOLOGY Physical pharmaceutics-II notes for B.pharm 4th sem students
 
math operations ued in python and all used
math operations ued in python and all usedmath operations ued in python and all used
math operations ued in python and all used
 
How to Create a More Engaging and Human Online Learning Experience
How to Create a More Engaging and Human Online Learning Experience How to Create a More Engaging and Human Online Learning Experience
How to Create a More Engaging and Human Online Learning Experience
 
Your Skill Boost Masterclass: Strategies for Effective Upskilling
Your Skill Boost Masterclass: Strategies for Effective UpskillingYour Skill Boost Masterclass: Strategies for Effective Upskilling
Your Skill Boost Masterclass: Strategies for Effective Upskilling
 
clinical examination of hip joint (1).pdf
clinical examination of hip joint (1).pdfclinical examination of hip joint (1).pdf
clinical examination of hip joint (1).pdf
 
Temple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation resultsTemple of Asclepius in Thrace. Excavation results
Temple of Asclepius in Thrace. Excavation results
 
Beyond Degrees - Empowering the Workforce in the Context of Skills-First.pptx
Beyond Degrees - Empowering the Workforce in the Context of Skills-First.pptxBeyond Degrees - Empowering the Workforce in the Context of Skills-First.pptx
Beyond Degrees - Empowering the Workforce in the Context of Skills-First.pptx
 
BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...
BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...
BÀI TẬP DẠY THÊM TIẾNG ANH LỚP 7 CẢ NĂM FRIENDS PLUS SÁCH CHÂN TRỜI SÁNG TẠO ...
 
Leveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit InnovationLeveraging Generative AI to Drive Nonprofit Innovation
Leveraging Generative AI to Drive Nonprofit Innovation
 
BBR 2024 Summer Sessions Interview Training
BBR  2024 Summer Sessions Interview TrainingBBR  2024 Summer Sessions Interview Training
BBR 2024 Summer Sessions Interview Training
 
B. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdfB. Ed Syllabus for babasaheb ambedkar education university.pdf
B. Ed Syllabus for babasaheb ambedkar education university.pdf
 
MARY JANE WILSON, A “BOA MÃE” .
MARY JANE WILSON, A “BOA MÃE”           .MARY JANE WILSON, A “BOA MÃE”           .
MARY JANE WILSON, A “BOA MÃE” .
 

C# classes

  • 1. C# - Classes Contents Authors Introduction Section I - Threads 1. Threads, Events and Mutextes 2. Internet Classes 3. Remoting Section II - Winforms 4. Controls 5. Data Handling 6. Printing Section III - Xml 7. Xml Classes 8. The DTD 9. Xml Data Document 10. Xml Documentation
  • 2. Authors Vijay Mukhi (vmukhi@vsnl.com) is one of the pioneers of the Indian Infotech Industry. For years, he has been the first to teach the emerging technologies in India thus ensuring that India always has people trained in technologies that the world requires. Vijay has written over 80 books on computers and programming over the last eight years on subjects ranging from C, C++ (The Odyssey Series) to Animation and Networking to Java to C#. Vijay abhors complexities and hence his books showcase the most difficult concepts explained through small programs, thereby giving a good understanding. Microsoft's .Net technologies is what Vijay is now focusing on and he aims at writing volumes on it. His knowledge on .Net Technologies is clearly visible in his four books where he explains the different concepts of the C# programming language in the most simplified form. Vinay Kalantri (vinaykalantri@yahoo.co.in) is a bright and enterprising software expert who has completed an extensive course in Business Management from a reputed University in the United States of America. He is presently undergoing rigorous training in software development in frontline applications. Sonal Mukhi (svmukhi@yahoo.com) is a freelance programmer having a widespread exposure to computer techniques and languages. Sonal has done groundbreaking work on various Internet Technologies like Java, ActiveX, Perl, C# and more. She has co-authored a few books on computer programming too. Introduction This book presents myriad fascinating concepts about C# classes. It is classified into three sections, with each of them converging on distinct facets of classes available in the .Net framework The curtains are raised with the chapter on Threads in Section I, which presents a nascent introduction to this topic. The topics of Events and Mutexes are also explored in detail. The next chapter is on the Internet related classes. Here, the utility of the Web classes and their role in building server and client applications are highlighted. The last chapter in this section takes on a different hue. It encapsulates the crux of writing programs to implement the concept of 'remoting'. This involves the composition of a client and a server program on different machines. The spotlight then moves on to the concept of Winforms in Section II. This chapter is replete with practical and useful insights into how Winforms can be put to optimum use in the .Net world. The C# language provides the facility of generating user-interfaces having aesthetic appeal, either by implementing the ready-to-use Form Controls, or by using controls crafted by us, in order to receive inputs from an end user. The subsequent chapter in this section delves upon the Database Controls. This chapter has been sedulously crafted, to capture the essence of this significant activity and to reveal its intricate details. The ubiquitous task of printing is the focus of the next chapter. The contents of this chapter will equip you to print output with practiced panache. The last section is devoted to XML, which is the most hyped language in the current market scenario. An XML file embodies an assortment of components, which will be unraveled, one at a time, in the chapters of this section. At the outset, the common XML classes have been highlighted, to provide an introduction to XML concepts, which are used while programming in the C# language. The next two chapters focus on DTD, which is an acronym for Data Type Definition, and also on the XML Data Document. They provide information on the various elements employed while generating an XML file. The topic of XML Documentation provides a hiatus from the preceding abstruse topics. It has been laced with effervescent text and examples to liven up the proceedings. We have applied utmost perspicacity to ensure that accurate, useful and relevant explanations, laced with lucid and practical examples, be presented to expound the various concepts to both, the amateur and the proficient programmer alike. We assure you that, by the time you disembark from this intellectual voyage of discovery, the various concepts that have been presented, are doubtlessly bound to create an indelible imprint on your minds. Requirements The software requirements to successfully run all the programs in this book are
  • 3. • Operating System - Windows 2000 • A Web Server preferably Microsoft IIS ver 5.0 • SQLServer 2000 (Evaluation Edition) • Internet Explorer 5.5 • .Net Framework SDK Beta 2 (111 MB) Internet Explorer 5.5 can be downloaded off the Microsoft site • http://www.microsoft.com/windows/ie/download/ie55sp1.htm Net Framework SDK Beta 2 can be downloaded off the Microsoft site • http://download.microsoft.com/download/VisualStudioNET/Trial/2.0/W982KMeXP/EN-US/setup.exe Alternatively, you can visit the download section at Microsoft ( http://msdn.microsoft.com/downloads/default.asp ) and download the .Net framework SDK Beta 2 under the Software Development Kit option. SQLServer 2000 While installing the evaluation edition of SQLServer 2000, we have chosen the default selected settings. The only modification made is in the Authentication Dialog Box. You see two options • Windows Authentication mode • Mixed mode (Windows Authentication and SQL Server Mode) The default option selected is Windows Authentication mode. We have instead selected Mixed mode (Windows Authentication and SQL Server Mode). Once this option is selected, the password text boxes for the 'sa' user gets activated. As we would prefer using a blank password in our programs, we select Blank Password. On selecting this option, the text boxes get disabled again. Acknowledgements The many individuals who have worked together to produce this great work of art and motivated me all the way need a mention here. Their bright ideas, inspiration, support has made me a lot more stronger and wiser. First and foremost, thanks to Manish Jain, BPB Publications for publishing the book. To my co-authors, Sonal and Vinay who have put in a lot of hard work to complete the work assigned to them. To Tanuja Sodhi, an ex-Naval Officer from the first batch of lady officers and an MBA from Jamnalal Bajaj, for editing the book. She is presently freelancing as a creative writer. To Altaf Hemani and Kishore Rohra, for their creativity in designing the cover in a given short time. Thanks to Manish Purohit for putting in all the time he had to verify the code with the explanations and then giving the book a good look and feel. To Pradeep Mukhi and Shivanand Shetty, who have always been there, as a source of inspiration and encouragement. My Mother, Shana Aunty and a long list of friends need a mention here for their patience and cooperation on this book while it was being written. -Vijay Mukhi
  • 4. 1 Threads, Events and Mutexes Threads operate on the premise that the computer is definitely more expeditious than a human at executing tasks, resulting in the computer idling away most of its processing time, waiting for the human operator. Threads are a means of overcoming this wastage of processing time. They perform multiple tasks on a computer in rapid succession, thereby, creating the illusion of these tasks being executed simultaneously. No application can ever be comprehensive without employing threads. Before we try to infer what a thread does in the programming context, let us rummage through a few examples given below. Without being discursive, let us venture out on our odyssey of understanding the concept of a thread with the assistance of a very diminutive program. a.cs using System.Threading; public class yyy { public static void abc() { System.Console.WriteLine("Hi"); } } public class zzz { public static void Main() { ThreadStart ts = new ThreadStart(yyy.abc); Thread t = new Thread(ts); System.Console.WriteLine("Before Start"); t.Start(); } } Output Before Start Hi This one is bound to leave you astonished because, we had earlier talked about starting out with a 'dimunitive' program. However, by no stretch of the imagination can the above program qualify as miniscule. Besides, the only work accomplished by this function is that it calls the static function abc, which in turn displays 'Hi'. In Main, we create an object ts, which is an instance of the class ThreadStart, which is derived from Delegate. Therefore, even though ThreadStart is a class, it also happens to be a delegate, whose constructor is given a static function called abc. Function abc is placed in the yyy class so that other classes can also use it. The program will work in a similar manner even if the static function is placed in class zzz. Next, we create another object t, which is an instance of Thread. The constructor of this object is given a ThreadStart object ts. Indirectly, ts stands for the static function yyy.abc since it is a delegate. So far, tranquility prevails and nothing transpires. The function yyy.abc too does not get called. But, as soon as we call Start off the thread, the function abc gets catapulted into action. Thus, the function abc is called only when the Start function is called. This is really no big deal. Note that classes beginning with Thread belong to the System.Threading namespace. a.cs using System.Threading; public class yyy { public void abc() { System.Console.WriteLine("Hi"); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc));
  • 5. t.Start(); } } Output Hi The above program is similar to the previous one and resembles the samples supplied by Microsoft. The function abc to be called, is non-static and hence, an object name is needed to reference it. The ThreadStart delegate object is directly passed as a parameter to the Thread constructor. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=3;i++) { System.Console.Write(i + " "); } } public void pqr() { for ( int i = 0; i<=3;i++) { System.Console.Write(i+ "..."); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.pqr)); t.Start(); t1.Start(); } } Output 0 1 2 3 0...1...2...3... The example embodies a very large amount of code. However, it does not create any fresh ripples in our pond of knowledge. We have merely created two Thread objects t and t1, and passed their constructors a different delegate or function name, i.e. abc and pqr, respectively. Thereafter, the Start function has been called in t and t1. Here, the function abc gets called, which displays four numbers. Thereafter, the function pqr gets called, which also displays four numbers, but with three dots. You may wonder with trepidation as to when you will bite into the real meat. Keep your impatience in abeyance for a little while ! a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=3;i++) { System.Console.Write(i + " "); Thread.Sleep(1); } } public void pqr() { for ( int i = 0; i<=3;i++) { System.Console.Write(i+ "..."); Thread.Sleep(1); }
  • 6. } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.pqr)); t.Start(); t1.Start(); } } Output 0 0...1 1...2 2...3 3... Now, we are at the threshold of excitement. By adding the function Sleep, which is a static function in the Thread class, the functions abc and pqr get called simultaneously, although not sequentially. This is how the concept of a thread is implemented, i.e. it empowers your computer to accomplish multiple jobs at the same time. This process is also termed as multi-tasking. Take the case of Microsoft Word. When you attempt to save a file, irrespective of the size of the file, Word appears to consume the same amount of time in completing this task. To expect it to save a 10MB file within a very short time period is a thought fraught with absurdity and contrary to reason. Actually, what the Word program does is that it creates a thread and then solicits the thread to save the file. While the thread is saving that file, another thread waits for the user to type something. Hence, the user is emancipated to continue working with Word. Thus, in effect, two tasks are being executed concurrently without the user being cognizant of it ! The same mechanism is employed by Excel and other similar products. Any application under Windows runs in its own thread. Thus, if two programs are launched, there will be two threads running. The operating system refrains from playing favorites and gives an equal amount of time to each thread to execute. If there are two threads co-existing, then, out of every minute of processing time available, each of them will be allotted 30 seconds to execute. If a third program is now executed, a new thread will be launched and each of the three threads will be allotted only 20 seconds of the processor time per minute to execute. If, instead of running a third program, what if the second program itself creates a thread ? As before, this will result in the creation of a third thread and each thread will be allotted 20 seconds of time. The resultant effect would be that that the first program will be allotted 20 seconds of time, whereas the second program will get 40 seconds per minute of the processor time. Thus, the larger number of threads that a program creates, more will be the processor time allotted to it. If you crave for more time and attention from your computer, desist from throwing a tantrum. Instead, generate greater number of threads. The computer allots a specific amount of time to each thread and then puts it to sleep. Thereafter, it executes another thread. The time given to each thread to execute its code is designated as a Time Slice. This allocation of Time Slices occurs so swiftly that each thread suffers from the hallucination that it enjoys the undivided attention of the computer. The static function Sleep in the Thread class facilitates this process. Sleep is like the sandman. It puts the thread to sleep for a certain number of milliseconds, as specified in its parameter. In this case, it is 1 millisecond. In the earlier example, in a single time slice, the Thread executed all the code and the function completed execution. In this case, the Sleep delays it long enough for the next thread to execute, and thus, the code in the functions get called one after the other. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=3;i++) { Thread t2 = Thread.CurrentThread; System.Console.Write(i + "." + t2.Name + " "); Thread.Sleep(1); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Name="One";
  • 7. t1.Name="Two"; t.Start(); t1.Start(); } } Output 0.One 0.Two 1.One 1.Two 2.One 2.Two 3.One 3.Two Here, we have provided mental catharsis by simplifying the program. What we actually have done is given the same function name abc to our delegate. We have also used the property Name of the Thread class to assign a distinct name to each thread, i.e. One and Two respectively. Under normal circumstances, the names assigned are pre-ordained by the system. Now, both the threads will call the same function abc. How do we determine as to which thread is calling the function abc? The Thread class can have members, which are either static or instance. CurrentThread is a static read-only property that returns a thread object, which represents the thread that has currently called the function. Here, Thread t2 will either represent t or t1, and the property Name will display the name of the thread executing the function. a.cs using System.Threading; public class zzz : Thread { } Compiler Error a.cs(2,14): error CS0509: 'zzz' : cannot inherit from sealed class 'System.Threading.Thread' The Thread class is a sealed class, therefore we cannot derive from it. The designers of the Thread class at Microsoft have held very doctrinaire opinions, in that, they believe that they have envisaged all the possible features required in this class. Thus, they have not provided any facility to override or modify it. Therefore, we are constrained to use the Thread class exactly as provided, without introducing any code that will complement or add to or subtract from the code of the Thread class. For your information, the Thread class in turn is derived from the interface ISerializable. a.cs using System.Threading; public class yyy { public void abc() { System.Console.WriteLine("Hi"); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); System.Console.WriteLine(t.IsAlive); t.Start(); System.Console.WriteLine(t.IsAlive); t.Abort(); System.Console.WriteLine(t.IsAlive); } } Output False True Hi False The Thread class has a property called IsAlive that reveals the current state of the Thread. When we create an object that looks like Thread, the thread is in a dead state and hence, the IsAlive property has a value of False. Start breathes life into the thread and executes through the delegate abc. The thread now comes alive, but the code in the thread function gets executed only after the subsequent WriteLine function, which displays the value of IsAlive as True. When we stop or Abort the Thread, the thread dies and the value of the property IsAlive reverts back to False. Thus, IsAlive can hold only one of the two values, False for dead or True for alive. a.cs using System.Threading; public class yyy {
  • 8. public void abc() { System.Console.WriteLine("Hi"); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); while ( !t.IsAlive ) System.Console.WriteLine("hi1"); } } Output Hi In today's world, we are working on extremely fast machines. When we execute t.Start(), the thread is brought to life in a fraction of a second. Hence, the while loop is not executed because the condition becomes false immediately. Had the machine been slower, the while loop may have got called a few times, as it would have taken some time before the thread could have been brought to life. Thus, the speed of execution may vary, depending upon the speed of the machine. Whenever the sample code creates a thread, it always contains this while loop. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=3 ; i++) System.Console.Write("Hi " + i + " "); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); System.Console.WriteLine("Over"); } } Output Over Hi 0 Hi 1 Hi 2 Hi 3 The executable, a.exe, runs in its own thread. So, before calling the function Start, we already have one thread running. On calling the function Start, two threads run concurrently, independent of each other. The second thread executes the function abc independent of the first thread. The first thread executes the last WriteLine function and then stops, whereas the second thread continues executing the function abc till there is no more code to call. If, on your machine, the first thread's time slice gets over before executing the WriteLine function, then some code of the function abc may get executed before Over gets displayed in the function Main. It is reiterated yet again that, in case of threads, there can be no guarantee as to when the time slice of a thread will get over. Even the operating system is not sagacious enough to offer any guarantees in this regard. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=3 ; i++) System.Console.Write("Hi " + i + " "); } } public class zzz { public static void Main()
  • 9. { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); t.Join(); System.Console.WriteLine("Over"); } } Output Hi 0 Hi 1 Hi 2 Hi 3 Over The function Join is a blocking function. It makes the program linger at the function Join till the thread finishes execution. Any code after the Join, in this case the WriteLine function, will be executed only after the thread dies. A blocking function will wait until the purpose it is waiting for has reached fructification. Thus, if we want to wait for a thread to complete execution, we use a Join. Join behaves like a party host, who is always the last to leave. a.cs using System.Threading; public class yyy { public void abc() { for ( ; ; ) ; } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); bool b = t.Join(10000); System.Console.WriteLine("Over " + b); } } Output Over False The Join function accepts a number as a parameter, which represents the maximum duration in milliseconds that it should wait for the thread to complete execution. In our example, the function abc will never end. Thus, the thread t will go on forever. Therefore, the Join function waits for 10 seconds, gives up and finally returns a False. Therefore, we are empowered to decide the duration for which we want to wait for the thread to complete execution. Let us not forget that our application has not yet terminated and is still hanging around in memory. At this stage, if you press Ctrl- Alt-Del, you will see a list of programs running. Now, select the End Task option for the program called 'a'. An alternative approach could be to add the Abort function t.Abort() after the WriteLine function. a.cs using System.Threading; public class yyy { public void abc() { for ( ; ; ) ; } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Join(); } } Output Unhandled Exception: System.Threading.ThreadStateException: Thread has not been started. at System.Threading.Thread.Join() at zzz.Main() If there is no thread running, the Join function will throw the exception of ThreadStateException.
  • 10. a.cs using System.Threading; public class yyy { public void abc() { System.Console.WriteLine("abc"); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); Thread.Sleep(3); t.Abort(); System.Console.WriteLine("Over"); Thread.Sleep(100); t.Start(); } } Output abc Over Unhandled Exception: System.Threading.ThreadStateException: Thread is running or terminated. Cannot restart. at System.Threading.Thread.StartInternal(IPrincipal principal, StackCrawlMark & stackMark) at System.Threading.Thread.Start() at zzz.Main() At first, we start the thread t by calling the Start function. Thereafter, we make the main thread sleep for a little while. Then, we abort the thread and again sleep for a little while, in order to enable the thread to fulfill its last wishes and finally die. Now that the thread is dead, we try and infuse life into it by calling Start again. A thread, which has died cannot be resuscitated. Since we have had the audacity to attempt this, the results are nearly cataclysmic, resulting in the generation of an exception which has to be caught. a.cs using System.Threading; public class yyy { public void abc() { System.Console.WriteLine("abc"); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); Thread.Sleep(3); t.Abort(); System.Console.WriteLine("Over"); Thread.Sleep(100); try { t.Start(); } catch (ThreadStateException e) { System.Console.WriteLine("In Exception"); } } } Output
  • 11. abc Over In Exception The exception thrown is ThreadStateException, which needs to be caught in our code. Otherwise, the runtime message box is displayed to the user. The Thread class constructor can throw two types of exceptions:- • ArgumentNullException - When it is called without a delegate in the constructor. • SecurityException - When the program does not have permission to create a thread. a.cs using System.Threading; public class yyy { public void abc() { System.Console.WriteLine("abc"); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); System.Console.WriteLine(t.ApartmentState); t.ApartmentState = ApartmentState.STA; t.Start(); System.Console.WriteLine(t.ApartmentState); } } Output Unknown STA abc We all have our own apartments, which are normally done up as per our preferences i.e. 'We are the kings of our castles'. Threads also have apartments. Any thread can be asked to execute either in a single-threaded apartment or in a multi- threaded apartment. These values can be established using the property ApartmentState, either once at the beginning, or while the thread is running. The various values that ApartmentState can assume are as follows: · STA : Single Threaded Apartment. · MTA : Multi Threaded Apartment. · Unknown : Default value assigned when no value is set. We, however, cannot use numbers for a string. Thus, an enum called ApartmentState has been used. It holds three values i.e. 0, 1 and 2 corresponding to STA, MTA and Unknown respectively. a.cs using System.Threading; public class yyy { public void abc() { System.Console.WriteLine("abc " + Thread.CurrentThread.IsBackground); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); System.Console.WriteLine("Main " + Thread.CurrentThread.IsBackground); t.Start(); } } Output
  • 12. Main False abc False A thread executes either in the background or in the foreground. The property IsBackground indicates the mode in which the thread will run. An important point to be noted here is that, a thread which executes in the background automatically shuts down when its main program quits. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0 ; i<=100; i++) { System.Console.WriteLine("abc " + i); Thread.Sleep(1); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); System.Console.WriteLine("Main " + Thread.CurrentThread.IsBackground); t.IsBackground = true; t.Start(); Thread.Sleep(10); } } Output (t.IsBackground = true) Main False abc 0 Output (t.IsBackground = false) Main False abc 0 abc 1 abc 2 .. .. abc 100 When you change the true to false in t.IsBackground, the output shows the code of function abc being executed. The for loop displays values from 0 to 100. By changing the property IsBackground of a thread to true, the thread terminates when the main program stops. Thus, the for loop does not have the time to display values upto 100. At times, the program displays abc with a value of 0. The sleeps are used to demonstrate the effect of the first thread shutting down and the second carrying on execution. On changing the property IsBackground to false, the thread takes its own sweet time to execute its code without any regard for the first thread, which may or may not have completed its job. So, the foreground threads behave exactly in the same manner as the background threads, when the property is initialized to true. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=10;i++) { System.Console.Write(i + " "); Thread.Sleep(1); } } public void pqr() {
  • 13. for ( int i = 0; i<=10;i++) { System.Console.Write(i+ "..."); Thread.Sleep(1); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.pqr)); System.Console.WriteLine(t.Priority); t.Priority = ThreadPriority.Highest; t1.Priority = ThreadPriority.Lowest; t.Start(); t1.Start(); } } Output Normal 0 1 2 3 4 0...5 1...6 2...7 3...8 4...9 5...10 6...7...8...9...10... We are at liberty to decide the duration of the time-slice to be allotted to our thread vis-a-vis other threads. This can be achieved by setting the Priority property accordingly. By default, the priority level is 2. Hence, we see 'Normal' displayed as the output. All threads start at this priority level. The ThreadPriority enum comprises of five levels of priority, which are as follows: • 0 - Zero • 1 - BelowNormal • 2 - Normal • 3 - AboveNormal • 4 - Highest In our program, we have changed the priority of thread t to the highest possible and that of thread t1 to the lowest. As a result, Thread t is accorded more time than thread t1, and it finishes its for loop much before thread t1 can do so. a.cs using System.Threading; public class yyy { public void abc() { try { System.Console.WriteLine("in abc"); for ( ; ; ) ; } catch ( System.Exception e) { System.Console.WriteLine("in abc Exception " +e.ToString() ); } finally { System.Console.WriteLine("in abc Finally"); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); Thread.Sleep(10); t.Abort(); } }
  • 14. Output in abc in abc Exception System.Threading.ThreadAbortException: Thread was being aborted. at yyy.abc() in abc Finally Aborting a Thread while it is busy executing some code generates an exception. Thus, the function abc will be sent an exception, resulting in a call to the 'catch' and 'finally' clauses. The thread will be terminated after executing the code in the Catch and the Finally clause. a.cs using System.Threading; public class yyy { public void abc() { try { System.Console.WriteLine("in abc"); for ( ; ; ) ; } catch ( System.Exception e) { System.Console.WriteLine("in abc Exception " +e.ToString() ); } finally { System.Console.WriteLine("in abc Finally"); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Abort(); t.Start(); } } Output (no output) Aborting a thread before it has started execution does not generate any exceptions, since the thread is in a dead state. Hence, no code in abc ever gets called. This situation is akin to the one where you don your best attire to watch cricket live at the stadium, but the show gets ruined due to heavy downpour, resulting in the match being abandoned without a ball being bowled ! a.cs using System.Threading; public class yyy { public void abc() { for (int i = 1 ; i<= 10 ; i++ ) { System.Console.Write(i + " " ); Thread.Sleep(1); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); Thread.Sleep(10); t.Suspend(); System.Console.WriteLine("n After Suspend");
  • 15. Thread.Sleep(10); System.Console.WriteLine("Before Resume"); t.Resume(); } } Output 1 After Suspend Before Resume 2 3 4 5 6 7 8 9 10 We are allowed to Suspend a thread executing its code, at any point in time. In the above program, we let the thread run for a little while and then Suspend it. Thereafter, we Resume it. Thus, the thread is like a puppet in our hands. We can decide when and which strings to pull and the thread does our biding. If the thread has already been suspended, then Suspending it once again has no effect, and thus, it does not result in an error. A single Resume is enough to undo a million Suspends. a.cs using System.Threading; public class yyy { public void abc() { for ( int i = 0; i<=3;i++) { Thread t2 = Thread.CurrentThread; System.Console.Write(i + " " + t2.GetHashCode() + " "); Thread.Sleep(1); } } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Start(); t1.Start(); } } Output 0 2 0 3 1 2 1 3 2 2 2 3 3 2 3 3 Every thread is assigned a number internally. This number is called the HashCode. Hashing is the process of assigning a number to an entity so that it can easily be located from a long list. This hash number is useful and is pressed into service when we are required to keep track of a large number of threads internally. a.cs using System.Threading; public class yyy { public void abc() { Monitor.Enter(this); for ( int i = 1; i<=5;i++) { System.Console.Write(i + " " + Thread.CurrentThread.GetHashCode() + " "); Thread.Sleep(1000); } Monitor.Exit(this); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Start();
  • 16. t1.Start(); } } Output 1 2 2 2 3 2 4 2 5 2 1 3 2 3 3 3 4 3 5 3 Let us now clarify the abstract concept of the life of a thread with the help of an example. Any resource that many people desire is called a shared resource. Imagine the chaos that would be caused if five programs tried to simultaneously use a single network printer for printing, during their respectively time-slices. This would result in the printer printing a few pages for program 1, then a few pages for program 2, and so on. The printer will keep printing merrily, but the printed output will all be jumbled up. Thus, ideally, one program should use a shared resource at a time, till its job is complete. For this, a method has to be implemented by means of which, unless one program finishes executing some specific code in a function, no other program should be allowed to execute it. Thus, all other programs would have to wait until the first thread finishes execution. Let us assume that function abc contains code which sends a request to the printer to print. The thread t gets the first shot at running abc. The second thread t1 has to wait until thread t finishes execution, even if the duration of executing abc takes more time than one time slice, due to a large value being assigned as a parameter to the sleep function. This is achieved by using the static function Enter of the class Monitor. The function Enter is given an object which refers to the class in which the function resides. From that point onwards, every thread has to wait at Enter. The barrier lowers only when Exit is called from the Monitor class. Enter acts as a fussy security guard who decides as to which thread is to be prohibited and which one is to be permitted to execute code. No two threads can ever enter the Enter function together. It is a rigid one way lane from Enter to Exit. One car is allowed in at one time and another car can pass through only after the first car leaves Exit. You can see that the names Enter and Exit have been chosen very aptly. a.cs using System; using System.Threading; public class ggg { }; public class yyy { public ggg g1; public void abc( ) { Monitor.Enter(g1); for ( int i = 1; i <= 3; i++) { Console.Write(" Hell " + i); Monitor.Wait(g1); Console.Write(" Waitabc " + i); Monitor.Pulse(g1); } Monitor.Exit(g1); } }; public class xxx { public ggg g1; public void pqr( ) { Monitor.Enter(g1); for ( int i = 1; i <= 3; i++) { Console.WriteLine(" Everyone " + i); Monitor.Pulse(g1); Monitor.Wait(g1); Console.Write(" Waitpqr " + i); } Monitor.Exit(g1); } }; public class zzz { public static void Main(String[] args) { ggg g = new ggg( ); yyy a = new yyy( );
  • 17. a.g1 = g; Thread t = new Thread(new ThreadStart(a.abc)); t.Start( ); xxx b = new xxx(); b.g1 = g; Thread t1 = new Thread(new ThreadStart(b.pqr)); t1.Start( ); } }; Output Hell 1 Everyone 1 Waitabc 1 Hell 2 Waitpqr 1 Everyone 2 Waitabc 2 Hell 3 Waitpqr 2 Everyone 3 cs Waitabc 3 Waitpqr 3 The above example may be a protracted one, yet it is fascinating. The world has never been able to work with each other. The only global body we have is the UNO. People are mostly loners. In the entry point function Main, we create an object g, which is an instance of a class ggg, having no code or variable. It embodies the emptiness of space. This is a class that is incapable of doing any good or bad. We then create two objects that look like yyy and xxx respectively, and pass them as delegates, so that the threads can call functions abc and pqr. We also initialize the object g1, an instance of ggg, in each of them to g. This is crucial. The g1's in yyy and xxx represent the same g that is created in Main. After initializing the requisite members, we activate the two threads. As earlier, let us assume that the function abc gets called first. Monitor.Enter considers taking a handle to any object, which is to be synchronized between multiple instances of threads, as its first parameter. This function needs an Exit function to release its handle. Thus, the number of Exits in the program must correspond to the number of Enters. It prints "Hell", and then due to the Wait function, it waits indefinitely, till it finally receives runtime notification. However, the thread accomplishes nothing significant. Thus, we do not see the Waitabc displayed, since it is entered after the Wait function. The second thread starts executing the function pqr. Monitor.Enter uses the same synchronized object, and now it displays Everyone. The next function to be called in pqr is Monitor.Pulse. Pulse does a very simple thing. It wakes up any thread having the same handle, which happens to be waiting at a Wait. Thus, the thread in abc wakes up. However, the one in pqr waits for someone to Pulse it. By using Wait and Pulse, we can easily play a game of tag. The thread t performs some work and waits for thread t1 to wrap up whatever work it is preoccupied with. Thread t does not know how long thread t1 will take to fulfill its side of the bargain. But no sweat! Thread t waits at a Wait for the thread t1 to Pulse it. Then, thread t1 waits at a Wait for thread t to do some work. When thread t concludes, it Pulses thread t1, and so on. This can go on and may involve some other threads too. The threads use the handle g, which is the synchronized region. It is akin to being an integral part of a clandestine social group. The parameter to these Monitor functions clubs them together as a group. If you change the handle, the group breaks up, leaving your thread in a lurch. The Wait function can also be made to wait for a specified time period. If we change the line Monitor.Wait(g1) to Monitor.Wait(g1,0), the output changes dramatically. A monitor is associated with an object on demand and it cannot be instantiated at all. If the constructor is private, we can never create an object. But, the static functions of that object can be used. The Monitor functions can be called from anywhere since they are unbound. There are no restrictions on the sources of the object to be called. a.cs using System.Threading; public class yyy { public void abc() { Monitor.Enter(this); Monitor.Enter(this); for ( int i = 1; i<=3;i++) { System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " "); } Monitor.Exit(this); } } public class zzz {
  • 18. public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Start(); t1.Start(); } } Output 1 2 2 2 3 2 The Exit function can be called as often as one desires. In this program, we have two threads, t and t1. Let us assume that thread t has the first go. At this time, it will pass through the first Monitor.Enter, as well as the second Monitor.Enter, without waiting at all. However, thread t1 will have to wait at the first Monitor.Enter, since the thread t called the Enter function twice, but Exited only once. Thus, the program never quits out. Had it called Exit twice, the thread t1 too would have woken up. a.cs using System.Threading; public class yyy { public int j=1; public void abc() { Monitor.Enter(j); for ( int i = 1; i<=3;i++) { System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " "); } Monitor.Exit(j); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); t.Start(); } } Output 1 2 2 2 3 2 Unhandled Exception: System.Threading.SynchronizationLockException: Exception of type System.Threading.SynchronizationLockException was thrown. at yyy.abc() Monitor.Enter takes an object, and not a variable, as a parameter. This is the reason why we used this parameter or some reference object, in the earlier programs. If a variable or a value object is used, an exception will be thrown. Thus, value types or null objects are not allowed as parameters to Monitor.Enter. a.cs using System.Threading; public class xxx { } public class ttt { } public class yyy { static int p = 1; xxx x = new xxx(); ttt t = new ttt(); public void abc() { if ( p == 1) { Monitor.Enter(x);
  • 19. p++; } else Monitor.Enter(t); for ( int i = 1; i<=3;i++) { Thread.Sleep(1000); System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " "); } Monitor.Exit(x); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Start(); t1.Start(); } } Output 1 2 1 3 2 2 2 3 3 2 3 3 The Enter function must be used with some caution. The variable p initially has a value of 1. The first thread t sees the value of p as 1. Hence, the 'if' statement is true. Thus, it crosses Monitor.Enter with x as a parameter. It then takes a snooze at the Sleep function, while the second thread t1 executes function abc, where it sees the value of variable p as 2. This thread now meets the Monitor.Enter function, with t as the parameter. The object reference given to this Enter is entirely at variance with the object given to the earlier one. Thus, both the threads execute the Enter function, which fails the very objective of the Enter function. For Enter to work as expected, it should be provided with the same object as a parameter to itself. The concept of a Lock is normally used to explain the Monitor class. One thread gets a Lock, while the others wait until the lock is released. a.cs using System.Threading; public class yyy { public void abc() { bool b = Monitor.TryEnter(this); System.Console.WriteLine(b); for ( int i = 1; i<=3;i++) { Thread.Sleep(1000); System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " "); } Monitor.Exit(this); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Start(); t1.Start(); } } Output True False 1 2
  • 20. 1 3 2 2 2 3 3 2 3 3 The TryEnter function is similar to the Enter function, but it does not block. If the thread enters successfully, TryEnter returns a true. This is what happens the first time. But in the case of the second thread t, it returns a false, even when it enters the critical section. a.cs using System.Threading; public class yyy { public void abc() { bool b = Monitor.TryEnter(this,1000); System.Console.WriteLine(b); for ( int i = 1; i<=3;i++) { Thread.Sleep(1000); System.Console.WriteLine(i + " " + Thread.CurrentThread.GetHashCode() + " "); } Monitor.Exit(this); } } public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Start(); t1.Start(); } } Output True False 1 2 1 3 2 2 2 3 3 2 3 3 The TryEnter function is overloaded to accept a number as a parameter, which represents the time duration for which the TryEnter function should block or wait. In our case, the timeout exceeds the time that thread t spends in the function. Hence, we get a value of False. If we add an extra zero to the time parameter, it will return a true instead. If the value of the parameter is infinite, the behaviour of the TryEnter becomes akin to that of Enter. Thread Attributes a.cs using System.Threading; public class yyy { [System.ThreadStaticAttribute ()] public static int j = 1; public static int k = 1; public void abc() { for ( int i = 1; i<=3;i++) { Thread t2 = Thread.CurrentThread; j++;k++; System.Console.Write(i + "." + t2.Name + " j=" + j + " k=" + k + " "); Thread.Sleep(1); } } }
  • 21. public class zzz { public static void Main() { yyy a = new yyy(); Thread t = new Thread(new ThreadStart(a.abc)); Thread t1 = new Thread(new ThreadStart(a.abc)); t.Name="One"; t1.Name="Two"; t.Start(); t1.Start(); } } Output 1.One j=1 k=2 1.Two j=1 k=3 2.One j=2 k=4 2.Two j=2 k=5 3.One j=3 k=6 3.Two j=3 k=7 A static variable is a loner, as reiterated by us on numerous occasions. It belongs to the class and not to an object. Thus, there will always be a single static variable. Let us consider a case where we have two threads t and t1 executing code in the same function abc, that also contains static variables j and k. The first question that strikes us is 'Will each of the threads see the same static variable or a different one?' Also, if we assume that both threads cater to the same static variable, when one thread increments the variable, will the other thread see the new value? And if not, then, is the compiler creating a separate static variable for each thread? Too many questions that need answers! We want to possess the best of both the worlds. At times, we need the threads to work on the same static variable, while at other times, we need the threads to access separate copies of the static variable. The default behaviour is that of the static variable being shared. Thus, the variable k is incremented by both the threads, and each thread sees the same value. The value of k finally reaches 7 at the end. The variable j has an attribute ThreadStaticAttribute above it. This attribute may have a fancy name, but it merely creates a separate variable for each thread executing the function. Thus, we have two static variables j, one for each thread t and t1. Any changes made to the value of the variable j by t, does not get reflected in the static variable j of the thread t1. 1.One j=2 k=2 1.Two j=3 k=3 2.Two j=4 k=4 2.One j=5 k=5 3.Two j=6 k=6 3.One j=7 k=7 The above attribute only acts on static variables. We see the above output when we remove static from the variables j and k. The compiler is very clear. The attribute ThreadStaticAttribute is only to be used on static variables, but when applied on non-static variables, the compiler does not generate any error or warning. It simply ignores the attribute. Thus, instance variables are shared across threads, whereas, local variables like i are independent of threads. Thus, a variable can either be shared across threads or may be independent of the thread. No in-between options are allowed. Events a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a; a = new ManualResetEvent(false) ; System.Console.WriteLine("Before WaitOne " ); bool b = a.WaitOne(1000,false); System.Console.WriteLine("After WaitOne " + b); } } Output Before WaitOne After WaitOne False We have created an object a that is an instance of a ManualResetEvent class. The constructor is assigned a value of false. Then, we call a function WaitOne from this class with a number as the first parameter, and a boolean value as the second parameter. This number, 1000, is the number of milliseconds for which we want the thread to wait at the function WaitOne. The thread therefore waits for one second before quitting out, and then returns a False. Had we used the enum Timeout.Infinite that has a value of -1, we could have made the function wait forever. Thus, we can keep a thread waiting either for a specified duration of time or forever. a.cs using System.Threading; public class zzz { public static void Main()
  • 22. { ManualResetEvent a; a = new ManualResetEvent(true) ; System.Console.WriteLine("Before WaitOne " ); bool b = a.WaitOne(1000,false); System.Console.WriteLine("After WaitOne " + b); } } Output Before WaitOne After WaitOne True By changing the value in the constructor to true, the thread just refuses to wait for anyone. It just whizzes past, without even acknowledging the presence of the function WaitOne. Further, the return value of WaitOne i.e. b returns a True. Let us delve a little deeper into this mystery. A ManualResetEvent is like a boolean variable. It can possess only one of the two values, true or false. When we first created such an object, we gave it a value of false. So, the function WaitOne waited till the Event object turned into True or the time value expired. Since the time duration got over while waiting, and the value of the Event object was not set to True, it stopped blocking and returned with a value of false. In the next example, the event object already has a value true and hence, there is no wait. Here, the function WaitOne returns true because the non-blocking in this case, cannot be attributed to a timeout. Thus, a ManualResetEvent has two states, true or false; or in technical lingo, signaled or non-signaled. A value of true implies a signaled state, while a false would mean that it is in the non-signaled state. a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a; a = new ManualResetEvent(true) ; System.Console.WriteLine("Before WaitOne " ); bool b = a.WaitOne(1000,true); System.Console.WriteLine("After WaitOne " + b); b = a.WaitOne(10000,true); System.Console.WriteLine("After second WaitOne " + b); } } Output Before WaitOne After WaitOne True After second WaitOne True Since we do not consider ourselves to be very cerebral, we shall desist from using fancy terminology like signaled or non- signaled. Instead, we shall stick to the simple true and false. We initially created the object a to be true or signaled (Oops! There we go again!). It then passed the first and the second WaitOne without waiting. This occurred because it is a Manual ResetEvent (as the name itself suggests), and not automatic. Once it is set to true, the event cannot change to false automatically. This has to be accomplished manually. a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a; a = new ManualResetEvent(true) ; System.Console.WriteLine("Before WaitOne " ); bool b = a.WaitOne(1000,true); System.Console.WriteLine("After WaitOne " + b); a.Reset(); b = a.WaitOne(10000,true); System.Console.WriteLine("After second WaitOne " + b); } } Output Before WaitOne After WaitOne True After second WaitOne False
  • 23. The Reset function can be used to change the state from true to false as it changes the state to false. Hence, it has to wait in queue like a commoner, since the event ignores the earlier WaitOne. After some time, it gets activated due to a timeout and the function WaitOne returns a False. a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a; a = new ManualResetEvent(false) ; System.Console.WriteLine("Before WaitOne " ); a.Set(); bool b = a.WaitOne(1000,true); System.Console.WriteLine("After WaitOne " + b); b = a.WaitOne(10000,true); System.Console.WriteLine("After second WaitOne " + b); } } Output Before WaitOne After WaitOne True After second WaitOne True Now, despite the fact that that the Event is originally false or non-signaled, the Set function sets it to true or the signaled state. At this stage, no power on earth is equipped to stop the event as it surges past the WaitOnes, treating them with disdain. It is not in the least concerned about stopping-by to pay homage to them. Such arrogance ! The class ManualResetEvent is a sealed class, like most other classes belonging to the Thread family. The developers at Microsoft were of the belief that no one would be able to add any more value to the class, and thus forbade any changes. This class is also derived from another class called WaitHandle, which in fact, embodies functions like WaitOne etc. The constructor has to be passed a parameter that affirms the initial state of the Event object. No default state is available. The Set and Reset methods return a boolean value, which indicates whether the change has taken place successfully or otherwise. WaitHandle is a class from which ManualResetEvent is derived. A class that offers functions which are polite, is called a synchronization class. People who are polite, wait for others to finish doing their work, and it is only then that they proceed with their own work. Any class that waits for another is called a synchronization class. All synchronization objects derive from WaitHandle, and so does ManualResetEvent. We are cautioned not to use this class directly, since it is the other classes that use this class. The documentation very clearly specifies that the CLR i.e. the Common Language Runtime or code written by Microsoft, calls the constructor of WaitHandle. Therefore, do not use this class directly. You are being forewarned! a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a,b; a = new ManualResetEvent(false) ; b = new ManualResetEvent(true) ; WaitHandle [] w = new WaitHandle[2]; w[0] = a; w[1] = b; System.Console.WriteLine("Before WaitAll " ); bool c = WaitHandle.WaitAll(w,10000,true); System.Console.WriteLine("After WaitAll " + c); } } Output Before WaitAll After WaitAll False We can complicate life as much as we like. Similarly, we can complicate the WaitOne, by introducing its elder brother, WaitAll. This function will wait for all the event objects to become true or signaled, or it will stay there till the timeout occurs. In this manner, life can be made as complicated as we like. Until all the events reach the signaled state, the WaitAll remains extremely stubborn and does not budge from its vantage position. It does not take cognizance if a few of the events are signaled. All the events should be signaled. This could be a number approaching infinity.
  • 24. a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a,b; a = new ManualResetEvent(false) ; b = new ManualResetEvent(true) ; WaitHandle [] w = new WaitHandle[2]; w[0] = a; w[1] = b; System.Console.WriteLine("Before WaitAll " ); bool c = WaitHandle.WaitAll(w); System.Console.WriteLine("After WaitAll " + c); } } Output Before WaitAll The number of functions in the class WaitHandle may be numerous, but most of them are only helper functions, which make life tranquil. The WaitAll function, if called with a single parameter, assumes that the second parameter is Timeout.Infinite or -1. These overloads can be ignored safely. It is the same for the WaitOne method. a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a,b; a = new ManualResetEvent(false) ; b = new ManualResetEvent(true) ; WaitHandle [] w = new WaitHandle[2]; w[0] = a; w[1] = a; System.Console.WriteLine("Before WaitAll " ); bool c = WaitHandle.WaitAll(w); System.Console.WriteLine("After WaitAll " + c); } } Output Before WaitAll Unhandled Exception: System.DuplicateWaitObjectException: Exception of type System.DuplicateWaitObjectException was thrown. at System.Threading.WaitHandle.WaitMultiple(WaitHandle[] waitHandles, Int32 millisecondsTimeout, Boolean exitContext, Boolean WaitAll) at System.Threading.WaitHandle.WaitAll(WaitHandle[] waitHandles, Int32 millisecondsTimeout, Boolean exitContext) at System.Threading.WaitHandle.WaitAll(WaitHandle[] waitHandles) at zzz.Main() The CLR (Common Language Runtime, if you have forgotten) never sleeps, but the compiler can be caught dozing at times. C# hates duplicates, and thus, we cannot pass the same handle to the WaitHandle array. If you attempt to do so, a runtime exception will be thrown even when there was no reason to throw an exception. The runtime could have simply ignored the duplicate, but it chose not to. a.cs using System.Threading; public class zzz { public static void Main() { ManualResetEvent a,b; a = new ManualResetEvent(false) ; b = new ManualResetEvent(true) ; WaitHandle [] w = new WaitHandle[2]; w[0] = b; w[1] = a; System.Console.WriteLine("Before WaitAll " ); int c = WaitHandle.WaitAny(w); System.Console.WriteLine("After WaitAll " + c);
  • 25. } } Output Before WaitAll After WaitAll 0 Change line containing w[0] = b; w[1] = a; to w[0] = a; w[1] = b; and the output changes to the following:- Output Before WaitAll After WaitAll 1 The WaitAny function waits till any of the events change to signaled or true. When this occurs, it returns the array index of the event which caused the exit. In this case, object b is in the signaled state, and since it is the first member of the array, the return value is 0. On interchanging the object to b, which is the second array member, the return value becomes 1. If both events are in the signaled state, then the lower array index is returned. If a timeout occurs, the value returned is 258. AutoResetEvent Class a.cs using System.Threading; public class zzz { public static void Main() { AutoResetEvent a; a = new AutoResetEvent(false) ; System.Console.WriteLine("Before WaitAll " ); bool c = a.WaitOne(1000,true); System.Console.WriteLine("After WaitOne " + c); } } Output Before WaitAll After WaitOne False Let us now move up the value chain. The AutoResetEvent class works in the same way like a ManualResetEvent class in the above example. It simply waits for the timeout to take place or the Event to be signaled. a.cs using System.Threading; public class zzz { public static void Main() { AutoResetEvent a; a = new AutoResetEvent(true) ; System.Console.WriteLine("Before WaitAll " ); bool c = a.WaitOne(1000,true); System.Console.WriteLine("After WaitOne " + c); c = a.WaitOne(10000,true); System.Console.WriteLine("After WaitOne1 " + c); } } Output Before WaitAll After WaitOne True After WaitOne1 False Ah! Again the wait. The AutoResetEvent object safely crosses the first WaitOne. But there is one major variation now in that, the state of the object changes from true to false or signaled to non-signaled. Thus, it is obliged to pay homage for some time at the second Wait. The name here is Auto and not Manual. Just as we would change color if we saw a wild boar charging at us, the AutoResetEvent changes state at the Wait. Everything else remains identical. Mutexes a.cs using System.Threading; public class zzz { static Mutex m;
  • 26. public static void Main() { m = new Mutex(true,"vijay"); zzz a=new zzz( ); Thread t= new Thread(new ThreadStart(a.abc)); t.Start(); } public void abc( ) { System.Console.WriteLine("abc start"); m.WaitOne( ); System.Console.WriteLine("abc end"); } } Output abc start If the boolean value of true in the Mutex constructor is changed to false, the output will change to the following:- Output abc start abc end A mutex is a synchronization object derived from the class WaitHandle. A Mutex is, in some sense, similar to the other Event classes. We commence by creating a mutex and assigning it a boolean value of either true or false. In this context, these values have a slightly different connotation. They decide whether the creating thread owns the object or not. True allows the thread to own it, whereas False does not. Thus, with a mutex, we need to become very materialistic and start taking ownership of things. The current thread owns the mutex while the other threads are inclined to own it. True or false, signaled or non-signaled, own it or not, are all the same concepts. The main thread already owns the mutex, which is named as vijay. The name is optional and is used mostly to refer to the mutex. Thereafter, we create a thread which calls the function abc. After displaying a message, the function WaitOne is called. This function will now stake a claim for ownership of the mutex, but since the main thread owns it, thread t cannot proceed beyond this function until the original thread gives up ownership. If we change the True in the constructor to False, then the ownership is not claimed. Thus, the thread t will not have to wait at the WaitOne as there is no owner. a.cs using System.Threading; public class zzz { static Mutex m; public static void Main() { m = new Mutex(true,"vijay"); zzz a=new zzz( ); Thread t= new Thread(new ThreadStart(a.abc)); t.Start(); } public void abc( ) { System.Console.WriteLine("abc start"); m.ReleaseMutex(); m.WaitOne( ); System.Console.WriteLine("abc end"); } } Output abc start Unhandled Exception: System.ApplicationException: Attempt to release mutex not owned by caller. at System.Threading.Mutex.ReleaseMutexNative(IntPtr handle) at System.Threading.Mutex.ReleaseMutex() at zzz.abc() The main thread becomes the owner of the mutex as the boolean value supplied in the mutex constructor is True. Then, in the function abc, we try to release the ownership of the mutex by using the function ReleaseMutex. The thread t does not own the mutex. Hence, we get a runtime error as only the owner i.e. the main thread, can release the ownership of a mutex and pass it on to another thread. a.cs using System.Threading;
  • 27. public class zzz { static Mutex m; public static void Main() { m = new Mutex(true,"vijay"); zzz a=new zzz( ); Thread t= new Thread(new ThreadStart(a.abc)); t.Start(); System.Console.WriteLine("Before Thread Sleep"); Thread.Sleep(10000); System.Console.WriteLine("After Thread Sleep"); m.ReleaseMutex(); System.Console.WriteLine("All over"); } public void abc( ) { System.Console.WriteLine("abc start"); m.WaitOne( ); System.Console.WriteLine("abc end"); } } Output Before Thread Sleep abc start After Thread Sleep abc end All over Now alls well that ends well. The main thread sleeps for a little while and then calls ReleaseMutex. This awakens the thread t, and thus, the function abc now quits out. Remember that you cannot give away what you do not own. a.cs using System.Threading; public class zzz { static Mutex m; public static void Main() { m = new Mutex(true,"vijay"); zzz a=new zzz( ); Thread t= new Thread(new ThreadStart(a.abc)); t.Start(); System.Console.WriteLine("Before Thread Sleep"); Thread.Sleep(1000); System.Console.WriteLine("After Thread Sleep"); m.ReleaseMutex(); System.Console.WriteLine("Before WaitOne"); m.WaitOne(); System.Console.WriteLine("All over"); } public void abc( ) { System.Console.WriteLine("abc start"); m.WaitOne(); System.Console.WriteLine("abc before sleep"); Thread.Sleep(100000); System.Console.WriteLine("abc end"); } } Output Before Thread Sleep abc start After Thread Sleep abc before sleep Before WaitOne There is a long sleep in the function abc. The mutex is still owned by the thread t, while the main thread is trying to regain its ownership. It can only gain ownership if the thread t releases the mutex or dies. Thus, until the thread t dies, we will not see
  • 28. All Over displayed at all. We could have had another sleep in abc and we could have released the mutex before that sleep. The choice is ours. Thus, a mutex is fully concerned with ownership issues. Either you own a mutex or you do not. a.cs using System.Threading; public class zzz { static Mutex m; static Mutex n; public static void Main() { m = new Mutex(true,"vijay"); n = new Mutex(true); zzz a=new zzz( ); Thread t= new Thread(new ThreadStart(a.abc)); t.Start(); System.Console.WriteLine("All over"); } public void abc( ) { System.Console.WriteLine("abc start"); Mutex [] g = new Mutex[2]; g[0] = m;g[1] = n; Mutex.WaitAll(g); System.Console.WriteLine("abc end"); } } Output All over abc start The program will hang. This is because we have two mutexses that have to be waited upon. Both m and n fill up the array g, and since both are true, the function abc will wait forever. Same rules of event classes apply to a mutex object. a.cs using System.Threading; public class zzz { static Mutex m; public static void Main() { m = new Mutex(true,"vijay"); zzz a=new zzz( ); Thread t= new Thread(new ThreadStart(a.abc)); t.Start(); System.Console.WriteLine("Before Thread Sleep"); Thread.Sleep(1000); System.Console.WriteLine("After Thread Sleep"); m.ReleaseMutex(); System.Console.WriteLine("Before WaitOne"); m.WaitOne(); System.Console.WriteLine("All over"); } public void abc( ) { System.Console.WriteLine("abc start"); m.WaitOne(); System.Console.WriteLine("abc after Wait"); m.WaitOne(); System.Console.WriteLine("abc after second Wait"); Thread.Sleep(10000); System.Console.WriteLine("End"); } } Output Before Thread Sleep abc start After Thread Sleep abc after Wait abc after second Wait Before WaitOne End
  • 29. All over The same rules about mutex ownership as mentioned earlier are discussed here. There may be two WaitOne functions, but the first WaitOne that gets the ownership, retains it. Thus, there was no wait between the first and the second wait. The concept of a mutex is extremely simple. A particular thread owns it. It can cross a wait without waiting and only when it releases the mutex can another thread claim and possess its ownership. Other threads cannot own it and they will have to wait at a wait. Dual ownership is not allowed. a.cs using System.Threading; public class zzz { static Mutex m; public static void Main() { m = new Mutex(false,"vijay"); zzz a=new zzz( ); System.Console.WriteLine("abc start"); m.WaitOne( ); System.Console.WriteLine("abc end"); } } Output abc start abc end A Mutex only works with multiple threads. So, using a mutex with a single thread is futile, because a mutex is concerned with determining as to which thread owns it. Therefore, there must be at least two threads. Timers a.cs using System.Threading; public class zzz { public static void Main() { zzz a = new zzz(); a.pqr(); } public void pqr() { Timer t; yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,100,0); Thread.Sleep(1000); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output hell Timers are time-related. We have created a timer object and have passed it 4 values in its constructor. The first parameter is the delegate object which represents the function that should be called after a certain interval elapses. The second parameter is the object to be passed to the timer function. The third and fourth parameters are numbers representing time i.e. time and period. If the thread is not asked to sleep, the main thread will quit out and there will be no thread running. The entire program will halt and all the unfired timers will die. Thus, if we remove the last Sleep, the word 'hell' does not get displayed. The timer delegate has to receive an object as a parameter since it is part of the delegate signature. The timer also has to wait for a specified time which is stated in the constructor, before it can call the function. This wait is accomplished using a thread in a thread pool. Needless to say, the Timer class is a sealed class. a.cs using System.Threading; public class zzz
  • 30. { public static void Main() { zzz a = new zzz(); a.pqr(); } public void pqr() { Timer t; yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,100,0); t.Dispose(); Thread.Sleep(1000); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output (none) If we ever desire to cancel the timer for whatever reasons, we can call the Dispose method to kill the timer. The timer dies and the function to be called does not get called at all. a.cs using System.Threading; public class zzz { public static void Main() { zzz a = new zzz(); a.pqr(); } public void pqr() { Timer t; ManualResetEvent e = new ManualResetEvent(false); yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,10000,300); t.Dispose(e); e.WaitOne(); System.Console.WriteLine("All Over"); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output All Over The Dispose function can also take a parameter which is an event that gets signaled when the timer dies. Thus, the program that would have waited indefinitely now quits out because, removing the timer from the timer queue instantly signals an event. a.cs using System.Threading; public class zzz { public static void Main() { zzz a = new zzz(); a.pqr(); }
  • 31. public void pqr() { Timer t; yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,100,1); Thread.Sleep(500); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output hell hell hell hell and so on The third parameter to the timer constructor is the duration in milliseconds after which the timer should be fired. The second number can be either a 0 or any other number. Zero means the timer fires once and any other number signifies it as a periodic timer. This periodic timer keeps executing the function abc every 100 milliseconds, until told to do otherwise. a.cs using System.Threading; public class zzz { public static void Main() { zzz a = new zzz(); a.pqr(); } public void pqr() { Timer t; yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,100,1); Thread.Sleep(115); t.Change(100,0); Thread.Sleep(1300); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output hell hell hell The Change function is used to stop a periodic timer. Thus, the timer can be made to run for some time in a periodic manner and thereafter, the Change can be used to stop it from executing repeatedly. a.cs using System.Threading; public class zzz { public static void Main() { zzz a = new zzz(); a.pqr(); } public void pqr() {
  • 32. Timer t; yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,100000,1); Thread.Sleep(115); t.Change(100,0); Thread.Sleep(1300); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output hell The timer initially is set to go off after a very long time. We let the main thread sleep for a little while but then change the due time of the timer to a smaller value. Thus, we can use the Change function to alter the initial settings of the timer. a.cs using System.Threading; public class zzz { public static void Main() { zzz a = new zzz(); a.pqr(); } public void pqr() { Timer t; yyy b = new yyy(); t = new Timer(new TimerCallback(b.abc),this,100,300); Thread.Sleep(1000); } } public class yyy { public void abc(object o) { System.Console.WriteLine("hell"); } } Output hell hell hell Our dictum has always been to understand things one step at a time. The last parameter to the timer constructor can either be zero or any other value. If the value is 100, it means that every hundred seconds the timer will go off, until it is stopped by a Change or a Dispose. Earlier, we had used the number 1 to signify that the timer should be called every 1 second. You are free to decide these timer values depending upon what you intend to use the timer for. The values cannot be negative and cannot exceed 4294967294 either. If you do so, an exception will occur. Exceptions, lest you have forgotten, are generated at runtime only. Thread Pool a.cs using System; using System.Threading; public class yyy { public ManualResetEvent a = new ManualResetEvent(false); public void abc(Object s) { a.WaitOne(10,true); Console.WriteLine("{0} ", Thread.CurrentThread.GetHashCode()); } }; public class zzz { public static void Main() {
  • 33. ManualResetEvent b = new ManualResetEvent(false); yyy y = new yyy(); for (int i=1;i<=5;i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(y.abc),1); } b.WaitOne(10000,true); } } Output 2 2 2 2 2 The rationale of a thread pool is that the decision makers at Microsoft did not want us to spend time taking care of threads like mothers take care of babies. We will first explain the above program and then delve into the nitty-gritty of thread pools. Since we are lazy, we use a for statement to avoid repeating the same code over and over again. The function QueueUserWorkItem will be called at least five times because it is placed in this for loop. QueueUserWorkItem function requires one, or at the most, two parameters. The first parameter, which is the name of a function, is most crucial. The name is never ever assigned directly, but indirectly, using a WaitCallback object. The function to be called is y.abc. Hence, it is passed a parameter to WaitCallback. The second parameter to the function QueueUserWorkItem is the number 1. As a result, the function abc has to accept a parameter of type object which will contain the value 1. A parameter of type object does not have any useful code and by itself is totally useless. Every entity in C# is finally derived from the object class. Thus, every entity is of an object type. Whenever we are not aware of the parameter type to be received in a function, or in cases where we want to receive multiple data types, the data type of object is used. Object is like a rubber man; it can fit anywhere and everywhere. By giving the function name abc to the function QueueUserWorkItem, abc will be called five times by a thread. The function waits for a small amount of time at an event and then uses the function GetHashCode to print the name/id of the thread. This function will print the thread id that is calling abc. From our output, we can conclude that only two threads execute the function abc. Commenting the Wait statement will display the same id for the thread. This means that no new thread executes the function. Thus, instead of two threads, only a single thread is used. Efficiency, thy name is Thread Pool. We are thus posting work items to a common place or thread pool. Then, a thread is allocated to execute the work item or function. The first available thread from the thread pool executes the function. We are only using one thread pool per program. There is a lot of overhead in managing threads. A lot of time is spent figuring out which thread is sleeping, i.e. waiting for an event to occur. Most of the time, threads are in this inert state. At times, threads wake up to check/poll for a change that is expected to occur, such as a key press, or to update some counter or status information and fall asleep again. Threads are like bears, they love sleeping. Thread Pooling is a means of managing threads more efficiently. This is done by providing your application with a pool of threads that are managed by the system. All threads that do work are called worker threads. There is a thread that monitors the status of threads waiting at any of the wait functions. When the wait is over, the callback function will be executed. The next program demonstrates how a function can be called after a specified time duration has elapsed. There is no way to cancel a function from being executed once it has gone into the thread pool. A prayer will also not help. Timers and Waits use the thread pool without our knowledge. The thread pool is created when we call the function QueueUserWorkItem for the first time or when we use a timer function. The number of threads that form part of a thread pool is limited by the amount of memory available. By today's standards, this means that more threads can be made available than we would ever need. These threads receive the default stack size and run at the default priority. No special priority is accorded. For the trivia fans, a thread can handle up to 63 wait operations. No concept is perfect. Thus, one significant disadvantage of a thread pool is that it involves a long calculation. a.cs using System; using System.Threading; public class yyy { public void abc(object s, bool b) { Console.WriteLine("{0} {1}", Thread.CurrentThread.GetHashCode(),b); } };
  • 34. public class zzz { public static void Main() { ManualResetEvent a = new ManualResetEvent(false); ManualResetEvent b = new ManualResetEvent(false); yyy y = new yyy(); ThreadPool.RegisterWaitForSingleObject(a,new WaitOrTimerCallback(y.abc),1,1000,true); b.WaitOne(10000,true); } } Output 2 True As mentioned earlier, we would like our function to be called after a certain wait. To accomplish this, we use a function with a very large name called RegisterWaitForSingleObject. The first parameter is the handle of an event. This has been set to false or non signaled. The second parameter is a delegate of type WaitOrTimerCallback which is similar to a WaitCallback. The difference is that the signature of the function given to this function, which is abc, has to have two parameters, viz. an object and a boolean variable. The third parameter is the object that is to be passed to the function. The second last parameter is a timer that decides the duration after which the function should be called. Finally, the last parameter decides whether the function is to be executed only once or every time the timer expires. As our event object is set to false, the function gets called after 1000 milliseconds. When the timer expires, the function abc obtains a value of true. By merely changing one line in the above example, the event can be changed to a signaled state. ManualResetEvent a = new ManualResetEvent(true); Output 2 False The function abc gets called immediately, unlike in the earlier program. Also, there is no wait as the event is true or signaled. The function abc also knows why it has been called since the bool parameter has a value of false, which was true in the earlier case. Thus, the function abc can look at the value of its second parameter, which indicates whether the timer has elapsed or the event has been signaled. a.cs using System; using System.Threading; public class yyy { public void Beta(object s, bool b) { Console.WriteLine("{0} {1}", Thread.CurrentThread.GetHashCode(),b); } }; public class zzz { public static void Main() { ManualResetEvent a = new ManualResetEvent(false); ManualResetEvent b = new ManualResetEvent(false); yyy y = new yyy(); ThreadPool.RegisterWaitForSingleObject(a,new WaitOrTimerCallback(y.Beta),1,10000,true); a.Set(); b.WaitOne(10000,true); } } Output 2 False In this program, initially we set the event to false and then, using the Set function, we set it to true immediately. Thus, the function gets called instantly. You would remember that the function gets called whenever the event is in a signaled state or the timer expires. This function first checks whether the wait object is signaled or not. If it is signaled, it executes the function. If it is not, it waits for the timer to elapse or the wait object to come into the signaled state, whichever occurs first. Interlocked a.cs using System;
  • 35. using System.Threading; public class yyy { public ManualResetEvent a = new ManualResetEvent(false); int i = 10; public void abc(Object s) { Interlocked.Increment(ref i); Console.WriteLine("{0} {1}", Thread.CurrentThread.GetHashCode(),i); } }; public class zzz { public static void Main() { ManualResetEvent b = new ManualResetEvent(false); yyy y = new yyy(); for (int i=1;i<=5;i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(y.abc),1); } b.WaitOne(10000,true); } } Output 2 11 2 12 2 13 2 14 2 15 Threads can be dangerous for the unwary. The function abc gets called five times by the same or a different thread. Consider a case where one thread may be incrementing the line i = i + 1. To do so, it will start by asking what is the value of i. Let us suppose that it is 10. It then increments the value by 1 to make it 11. It may so happen that just as it is about to read its value, its time slice may get over and another thread may increment the variable i by 1 to make its value 12. When the first thread receives its next time slice and checks the value of i, it will see the value as 12 and not 11. Thus, the variable would have been incremented twice instead of once. The Interlocked class has a sole purpose in life, i.e. to ensure that the variables are not incremented more than once. In a sense, it synchronizes access to a variable that is being shared by a number of threads. The operation will either be done in a single time slice or not done at all. It will not be carried over into another time slice ever. These operations, which are guaranteed to be finished in a single time slice, are called atomic operations. a.cs using System; using System.Threading; public class yyy { public ManualResetEvent a = new ManualResetEvent(false); public int i = 10; public void abc(Object s) { i++; Interlocked.CompareExchange(ref i,100,12); } }; public class zzz { public static void Main() { ManualResetEvent b = new ManualResetEvent(false); yyy y = new yyy(); for (int i=1;i<=5;i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(y.abc),1); } b.WaitOne(1000,true); Console.WriteLine(y.i); } } Output
  • 36. 103 The function abc gets called five times. If we intend to carry out comparisons, we would face the above dilemma. Thus, we use a simple function called CompareExchange. This functions checks the value of the first parameter that is passed as a reference, with the third parameter, which in our case is 12. If it matches the value, the first parameter i.e. i is assigned the value of the second parameter i.e. 100. All this is done in a single time slice. Thus, whenever variable i becomes 12, its value shoots up to 100, and as a result, the final answer becomes 103. Like the Increment, there is a Decrement function also that reduces the value of a variable by one. As an aside, a ref parameter cannot be replaced by an out parameter. In the same vein, the Exchange function changes the value of two variables passed to it as ref parameters. This is done in an atomic manner. 2 Internet Classes Before weaving our way into the Internet, let us investigate a few more fundamentals about the C# programming language, in order to acquire a superior appreciation of internet programming. No computer in the world is equipped to recognize the letters of the alphabet on its own. Therefore, an internal representation has to be used. One such representation is called ASCII, which allots a number falling between 0 to 255, to each of the letters. Here, each letter is represented by a byte, which is an 8-bit number. For instance, the letter 'A' is represented by the number 65, while the letter 'a' is represented by the number 97. However, languages such as Japanese and Chinese are remarkably visual, and require a larger range of numbers to represent them in totality. In order to accommodate the requirement of these languages, the computer industry came out with a standard called UNICODE, which can represent every known language in the world in its entirety. But, to accomplish this, this standard imposes the condition that every character in the language should be represented by a 16-bit number, and not by an 8-bit number. a.cs public class zzz { public static void Main() { byte i = 65; System.Console.WriteLine(i); System.Console.WriteLine((char)i); i = (byte)'A'; System.Console.WriteLine(i); } } Output 65 A 65 The C# language takes cognizance of the fact that the byte data type represents a number ranging from 0 to 255. Thus, by default, the WriteLine function displays the number that the byte represents. If we typecast the byte i to a char, the WriteLine function displays its ASCII equivalent instead. The C# language had to indoctrinate a new data type called 'char', which could represent a UNICODE character or a number ranging from 0 to 65535, since a byte is too diminutive to be able to accommodate this range of values. A literal or char 'A' cannot be initialized to a byte, since we cannot equate a smaller 8-bit data type to a larger 16-bit data type. Therefore, a cast operator has to be used. a.cs public class zzz { public static void Main() { char i = 'A'; System.Console.WriteLine(i); } } Output
  • 37. A A variable of char data type cannot be equated to a number. It can only be initialized to a literal. The WriteLine function prefers to receive the 'char' data type, since it can display the value as a letter of the alphabet. Thus, the 'char' data type is used to store 16 bit UNICODE characters, while the 'byte' data type is employed to store small numbers. The 'string' data type is used for a sequence of UNICODE characters. a.cs public class zzz { public static void Main() { byte [] i = new byte[5]; i[0] = 65; i[1] = 66; System.Console.WriteLine(i); char [] j = new char[5]; j[0] = 'A'; j[1] = 'B'; System.Console.WriteLine(j); } } Output System.Byte[] AB Dealing with an array of bytes is not as straightforward and uncomplicated as dealing with an array of chars. In case of an array of bytes, the WriteLine function merely displays the data type of the array, whereas, in the case of an array of chars, it displays the entire array. Thus, we need a technique, by means of which, we are able to display the bytes present in the form of an array of bytes, using the WriteLine function. a.cs public class zzz { public static void Main() { byte [] i = new byte[5]; i[0] = 65; i[1] = 66; i[2] = 67;i[3] = 68; string s = System.Text.Encoding.ASCII.GetString(i, 1, 2); System.Console.WriteLine(s); } } Output BC The namespace System.Text.Encoding has a class called ASCII, which contains a static function GetString. This function accepts three parameters: • The array of bytes, which is to be converted into a string. • The starting point in the array ( in our case, 1) refers to the second element in the Array, which is the letter 'B'. • The number of characters or the length of the string. We have specified it as 2. Hence, only 2 characters are seen. The function returns a string, which is displayed by employing the WriteLine function. This methodology thereby, assists in converting a certain number of bytes from a byte array into a string, which can then be effortlessly printed by the WriteLine function. The rationale for introducing this function in this chapter is due to the existence of a large number of functions that return data as an array of bytes. The approach demonstrated above may be employed, to display such data in all such cases. a.cs public class zzz { public static void Main() { string s1 = "vmukhi"; byte[] i; char [] j = s1.ToCharArray(); i = System.Text.Encoding.ASCII.GetBytes(j); string s = System.Text.Encoding.ASCII.GetString(i, 0, 5); System.Console.WriteLine(s); } }
  • 38. Output vmukh We now need to resolve another quandary. In the internet-related classes, functions read and write data in the form of an array of bytes. We are comfortable dealing with strings, as they are the most natural data type available for representing data. However, this data type has to be converted into an array of bytes, if it has to be transmitted. But, there is no direct mechanism of attaining this conversion. The only possibility is to write our own function. The string is first converted into an array of chars, using ToCharArray method in the string class. As of now, there exists no magic formula in the string class, which can directly provide an array of bytes. So, we are compelled to utilize the GetBytes function from the ASCII class, which accepts a character array and converts it into an array of bytes. This is an additional step that needs to be executed in the conversion process. The last two lines of the above program merely verify whether all data has been supplied correctly or otherwise. a.cs public class zzz { public static void Main() { byte [] a; a= abc("ABC"); string s = System.Text.Encoding.ASCII.GetString(a, 0, 3); System.Console.WriteLine(s); } public static byte [] abc( string a) { byte [] b = new byte[a.Length]; System.Console.WriteLine(a.Length); for ( int i = 0 ; i < a.Length ; i++) { System.Console.WriteLine(a[i]); b[i] = (byte)a[i]; } return b; } } Output 3 A B C ABC In this program, we write our own function that accepts a string as a parameter, and returns an array of bytes. This function eliminates the intermediate step of converting the string into an array of chars, prior to its final conversion into an array of bytes. The Length member in the string returns the length of the string, and also determines the size of the byte array, which is to be created. In the 'for' loop, every individual character can be accessed, one at a time, by using the indexer property of the string class. Concurrently, the byte array is also filled up. The need for a cast operator has been explained earlier. Finally, at the end of the function, we return this freshly filled up array, and thereafter, display the byte array. The array is displayed merely to corroborate that all actions have been executed as planned. File Handling a.cs using System; using System.IO; class zzz { public static void Main() { FileStream f = new FileStream("c:z.txt", FileMode.Open, FileAccess.Read); byte [] a; a = new byte[512]; int b = f.Read(a, 0, 512); Console.WriteLine(b); string s = System.Text.Encoding.ASCII.GetString(a, 0, b); Console.Write(s);
  • 39. } } z.txt vijay mukhi Output 12 vijay mukhi We start by creating an object f, which is an instance of class FileStream. The function is assigned the name of the file that we want to work with, along with the mode in which it is to be opened. The two parameters, FileMode.Open and FileAccess.Read, are enums, which open a file for reading. The Read function in the file stream reads the file. The function has 3 parameters: • The first parameter is a byte array. The data from the file is to be read into this array. • The second parameter is the offset position. • The third parameter is the maximum number of bytes to be read. Thus, the Read function shall attempt to read upto 512 bytes from the file, until it reaches the end of the file. Since the file contains only the words 'vijay mukhi', the output is 12, which represents the number of bytes read. This is followed by the data, i.e. vijay mukhi. Let us now browse through the data sent by a web server. a.cs using System; using System.Net; using System.IO; class zzz { public static void Main() { WebRequest r = WebRequest.Create("http://www.vijaymukhi.com"); WebResponse re = r.GetResponse(); Stream s = re.GetResponseStream(); Byte[] a = new Byte[51200]; int b = s.Read(a, 0, 51200); Console.WriteLine(b); Console.Write(System.Text.Encoding.ASCII.GetString(a, 0, b)); } } Output 1085 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frame.dtd"> <html> <head> <title>Vijay Mukhi's Technology cornucopia</title> </head> <frameset frameborder="0" framespacing="0" border="0" cols="*" rows="97,*"> <frame marginwidth="0" marginheight="0" src="heading.html" name="heading" noresize scrolling="no"> <frameset frameborder="0" framespacing="0" border="0" cols="210,*" rows="*"> <frameset frameborder="1" framespacing="0" border="0" cols="*" rows="0,*"> <frame marginwidth="0" marginheight="0" src="code.html" name="code" noresize scrolling="no" frameborder="0"> <frame marginwidth="5" marginheight="5" src="menu_empty.html" name="menu" noresize scrolling="auto" frameborder="0"> </frameset> <frame marginwidth="5" marginheight="5" src="main.html" name="text" noresize> </frameset> <noframes> <p>The <code>NOFRAMES</code> element is to be used to give useful content to people with browsers that cannot display frames. One example is Lynx, a text-based browser.</p> </noframes> </frameset> </html> We expect you to either have a web server installed on your machine, or at least be connected to the net. Every machine on the internet is recognized by a name. For example. the Microsoft site is known as www.microsoft.com; the Java site on the net is known as www.javasoft.com; and my site is known as www.vijaymukhi.com. However, every machine
  • 40. is also known by the common name of 'localhost'. When the address specified in the browser is www.microsoft.com, the web server of that machine sends across an HTML file to the browser. The file that is sent across is either named index.html or default.html. In the above program, we would like to simulate the functioning of a browser, i.e. we want to fetch an HTML file from a web server. In the System.Net namespace, there is a class called WebRequest that has a static function called Create. This function requires the name of the machine that runs a web server. While reading this book, in case you are not connected to the Internet, you may use 'http://localhost/' as the name of the machine. Or else, you may connect to a site on the net such as www.vijaymukhi.com. A WebRequest object r is returned by the Create function. The WebRequest class has another function called GetResponse, which returns a WebResponse object. The value returned is stored in a variable called re. Calling the method GetResponseStream from the WebResponse object returns a Stream object that can be utilized to read the HTML file sent across by the web server. The file handling concepts, learnt a short while ago, may be applied here too. The interaction between our program and the web server is handled by two classes, i.e. WebRequest and WebResponse. We have no inkling as to what each class accomplishes. In order to read the HTML file off the Stream object, we create a byte array having a size of 51200. Thereafter, we employ the Read function to read 51200 bytes, from the inception of the stream, into the array. The value returned by the Read function is indicative of the number of bytes that have been read off the stream. On displaying this value, the number obtained is less then 51200 (in our case it is 1085), and not 51200. Therefore, despite our having commanded the Read function to read upto 51200 bytes, it read only 1085 bytes. This is because it encountered an End Of File mark after having read 1085 bytes. In case of an error, the WebResponse object displays a Status code. Few of the values that may be assigned to this Status code, are as follows: • 200 indicates 'success'. • 403 indicates 'permission denied'. • 404 indicates that the 'file name does not exist'. Since no errors are visible in our case, we assume the status code to be 200. Thereafter, the byte array is converted into a string, so that it can be displayed using the GetString function. Therefore, we see the first 1085 bytes of the HTML file, sent by the web server. a.cs using System; using System.Net; using System.IO; class zzz { public static void Main() { WebRequest r = WebRequest.Create("http://www.yahoo.com"); WebResponse re = r.GetResponse(); Stream s = re.GetResponseStream(); Byte[] a = new Byte[51200]; int b = s.Read(a, 0, 51200); while (b > 0) { Console.Write(System.Text.Encoding.ASCII.GetString(a, 0, b)); b = s.Read(a, 0, 512); System.Console.WriteLine(b); } } } We are not in a position to estimate the file size of the HTML file, which has been sent by the web server. So, we take recourse to the 'while' loop in situations of incertitude or perplexity. The Read function returns a zero, when there is no more data to be read from the stream. Thus, the 'while' loop terminates when the value of b becomes zero. Therefore, the last line of the output would always display a zero. In fact, we can regulate the number of bytes that we want the Read function to read off the stream. Here, we specify a value of 512. The framework enjoys the license to ignore this number. In order to retrieve a specific file off the web server, such as a.html, we add the name of the file at the end of the URL. If the file appertains to the local hard disk, the Create function will be written as follows: WebRequest r = WebRequest.Create("http://localhost/a.html");
  • 41. The next query which is likely to vex our minds is: Where would the file a.html be stored on the hard disk? The answer to this depends upon the web server installed on the machine. In case of IIS or PWS from Microsoft, the file a.html would be placed in the sub-directory c:inetpubwwwroot. Reading a file sent by a web server is similar to reading a file from the local disk. Therefore, we do not have to discover two separate ways of reading the same thing. a.cs using System; using System.Net; using System.IO; class zzz { public static void Main() { Uri u = new Uri("http://www.yahoo.com"); HttpWebRequest wr = (HttpWebRequest) WebRequest.Create(u); AsyncCallback a = new AsyncCallback(abc); IAsyncResult r = (IAsyncResult) wr.BeginGetResponse(a,wr); Console.ReadLine(); } static void abc(IAsyncResult ar) { HttpWebRequest r = (HttpWebRequest) ar.AsyncState; HttpWebResponse re = (HttpWebResponse) r.EndGetResponse(ar); Stream s = re.GetResponseStream(); Console.WriteLine("Status code: " + re.StatusCode); Byte[] a = new Byte[51200]; int b = s.Read(a, 0, 51200); while (b > 0) { Console.Write(System.Text.Encoding.ASCII.GetString(a, 0, b)); b = s.Read(a, 0, 512); System.Console.WriteLine(b); } } } The above program displays the same output as before, but with a difference. It follows a dissimilar method of writing code. In the previous example, the Read function waited till the data was received from the Internet. When we are connected to the Internet, this wait could be indefinite. This effectively would disable the program from proceeding any further. While awaiting data, the program cannot carry out any other activity. Thus, to avoid squandering of time and resources, we need a mechanism, by means of which, the program can be intimated about the receipt of data for the HTML file. The static function Create, now accepts a URI as a parameter. To create this URI object, we pass the same URI string as a parameter to the constructor. The return value of this function is stored in a HttpWebRequest object, since this class is derived from the class WebRequest. This class has a function BeginGetResponse, which accepts two parameters. The first is an AsyncCallback delegate, which requires the name of a function. In the C# world, a delegate simply stands-in for a function to be called. The second parameter is a State object. Despite our not making any use of any state related information, we are not allowed to supply a null value. It is mandatory to supply a value, without which, an error is generated. Thus, we specify the object wr, of type HttpWebRequest, as the parameter. Under normal circumstances, we are required to create a State object and furnish it as a parameter. After a certain time duration, data arrives from the web server, and the function abc gets called. This function is passed IAsyncResult as a parameter, which has a property AsyncState. Since this is an Object, we cast it to HttpWebRequest. We require an HttpWebResponse object, in order to obtain a Stream object, which will be employed to read the file received from the web server. The HttpWebRequest class has a EndGetResponse function, which accepts an IAsyncResult as a parameter, and returns a HttpWebResponse object. This object, in turn, is derived from the HttpResponse class. This function terminates the asynchronous request. The remaining code is similar to the above program. We however, are at liberty to execute other tasks, while the file is being received. Normally, a separate thread runs the function abc in an asynchronous manner. a.cs using System; using System.Net; using System.IO; class zzz { public static void Main() { Uri u = new Uri("http://www.yahoo.com");