A program executes as a single, sequential flow of control. A program can also be designed to execute multiple tasks. To execute multiple tasks in your program, you can use threads. This chapter discusses implementation of threads and their life cycle. The chapter also discusses implementing multiple threads and prioritizing threads. In addition, this chapter discusses thread synchronization and communication between processes.

Objectives In this chapter, you will learn to:  Implement threads  Define the life cycle of a thread  Implement multiple threads  Identify the thread priority  Use synchronization in threads  Identify communication between processes

Chapter 11

Creating Multithreaded Applications

Implementing Threads A thread is defined as the execution path of a program. You can define a unique flow of a control in a program, using a thread. Threads are used to run applications that perform large and complex computations. For example, a Central Processing Unit (CPU) performs various complex tasks simultaneously. The processes include tasks such as writing and printing a document, installing software, and displaying the date and time on the status bar. All these processes are handled by separate threads. A process that is executed using one thread is known as a single-threaded process, where the process is a running instance of a program. A single-threaded application can perform only one task at a time. You have to wait for one task to complete before another task can start. The following figure shows a single-threaded process.

A Single-Threaded Process

To execute more than one task at a time, you can create multiple threads in a program. A process that creates two or more threads is called a multithreaded process. For example, any Web browser, such as Internet Explorer is a multithreaded application. Within the browser, you can print a page in the background while you scroll the page. Similarly, you can play audio files and watch animated images at the same time. Each thread in a multithreaded process runs at the same time and maintains a different execution flow. The following figure shows a multithreaded process with two threads.

A Multithreaded Process

¤NIIT

Creating Multithreaded Applications 11.3

The Thread Model A program uses threads to increase the efficiency of a CPU by preventing wastage of the CPU cycles. In single-threaded systems, an approach called event loop with polling is used. Polling is the process in which a single event is executed at a time. In the event loop with polling approach, a single thread runs in an infinite loop till its operation is completed. When the operation is completed, the event loop dispatches control to the appropriate event-handler. No more processing can happen in the system until the event-handler returns. This results in the wastage of the CPU time. In a single-threaded application if the thread is suspended from execution because it is waiting for a system resource, the entire program stops executing. This limitation can be overcome by using multithreading, which eliminates the event loop with polling approach. In multithreading, the time for which a thread waits for the CPU time can be utilized to perform another task. In C#, you will use the Thread class to work with threads. The System.Threading.Thread class is used to construct and access individual threads in a multithreaded application. The first thread to be executed in a process is called the main thread.

The Main Thread The main thread is created automatically on the start up of a C# program execution. The threads which are created exclusively using the Thread class are called as child threads, where the main thread is either called a parent thread or a primary thread. You can access a thread using the CurrentThread property of the Thread class. The following code shows the execution of main thread using its CurrentThread property in the Thread class: using System; using System.Threading; namespace ThreadExample { class MainThreadExample { public static void Main(string[] args) { Thread Th = Thread.CurrentThread; Th.Name = "MainThread"; Console.WriteLine("The current thread after name change :{0}", Th.Name); Console.ReadLine(); 11.4 Creating Multithreaded Applications

¤NIIT

}

}

}

The output of the preceding code is as follows.

Output of the Main Thread Program

In the preceding code, a reference to the current thread is obtained by using the CurrentThread parameter of the Thread class and its reference is stored in the Th variable. The Name parameter is used to set the name of the thread, and the information about the thread is displayed.

Working with Threads In C#, you create a thread by creating an object of type Thread, giving its constructor a and calling the new thread’s Start() method. The new thread starts executing asynchronously with an invocation of the thread’s method. When the method returns, the thread dies. ThreadStart reference,

The other methods of the Thread class allow managing the lifetime of the thread and destroying the thread when required. There are various methods available with the Thread class. Using these methods, you can control the execution of threads. Few of these methods are: „ Start(): Starts a thread „ Sleep(): Makes the thread to pause for a period of time ¤NIIT

Creating Multithreaded Applications 11.5

„ „ „

Abort():

Terminates the thread Suspend(): Suspends a thread. If the thread is already suspended it has no effect Resume(): Resumes the suspended thread

Working with threads involves creating, managing, and destroying threads.

Creating Threads You can create threads by extending the Thread class. The extended Thread class calls the Start() method to begin the child thread execution. You can use the following code to create a thread by extending the Thread class: using System; using System.Threading; namespace ThreadSample { class BasicThreadApp { public static void ChildThreadCall() { Console.WriteLine("Child thread started"); } public static void Main() { ThreadStart ChildRef = new ThreadStart(ChildThreadCall); Console.WriteLine("Main - Creating Child thread"); Thread ChildThread = new Thread(ChildRef); ChildThread.Start();

} }

Console.WriteLine("Main - Have requested the start of child thread"); Console.ReadLine();

}

11.6 Creating Multithreaded Applications

¤NIIT

The output of the preceding code is as follows.

Output of the Create Thread Program

In the preceding output, the Main() method prints before the message from the child thread, proving that the child thread is indeed working asynchronously. The first statement in the preceding code is the using statement for the System.Threading namespace. The first statement of the Main() method specifies the method to be invoked by the thread: ThreadStart ChileRef = new ThreadStart(ChildThreadCall);

The next statement instantiates a Thread object where the constructor takes the object of the ThreadStart class as its argument: Thread ChildThreads = new Thread(ChildRef);

Then, the Start() method of the Thread object is called, and the method results in a call to the ChildThreadCall method. The extended Thread class calls the Start() method to begin the child thread execution.

Managing Threads There are many tasks you might need to perform to manage the activity or life of a thread. You can manage all these tasks by using the various thread methods available with the Thread class. ¤NIIT

Creating Multithreaded Applications 11.7

For example, when you require the thread to pause for a period of time so that the thread is allowed to execute, you can call the Thread.Sleep() method. This method takes a single argument that represents time in milliseconds for which you want the thread to pause. This method is a static method and cannot be called with an instance of a thread object. This is done to avoid a call to the Thread.Sleep() method on any other thread except the currently executing method. The static Thread.Sleep() method calls the static CurrentThread method, which then pauses that thread for the specified amount of time. The following code shows the implementation of the Sleep() method: using System; using System.Threading; namespace ThreadSample { class BasicThreadApp { public static void ChildThreadCall() { Console.WriteLine("Child thread started"); int SleepTime = 5000; Console.WriteLine("Sleeping for {0} seconds", SleepTime/1000); Thread.Sleep(SleepTime); //Sleep for five seconds. Console.WriteLine("Waking Up"); } public static void Main() { ThreadStart ChildRef = new ThreadStart(ChildThreadCall); Console.WriteLine("Main - Creating Child thread"); Thread ChildThread = new Thread(ChildRef); ChildThread.Start(); Console.WriteLine ("Main - Have requested the start of child thread"); Console.ReadLine(); }

}

}

11.8 Creating Multithreaded Applications

¤NIIT

The output of the preceding code is as follows.

Output of the Managing Threads Program

There is more than one way to call the Sleep() method. One way is to call Thread.Sleep() with a value 0, which will cause the current thread to hand over the unused balance of its timeslice. The other way is to call Thread.sleep() method with a value of Timeout.Infinite, which results in the thread being paused indefinitely until it is interrupted by another thread calling the suspended thread’s Thread.Interrupt() method. There is another method Thread.Suspend(), which is used to suspend the execution of a thread. The Thread.Suspend() method can be called on the currently executing thread or another thread. When a thread is suspended in this fashion, only another thread can cause its resumption, with the Thread.Resume() method. Notice, when a thread suspends another thread, the first thread is not blocked. The call returns immediately. In addition, regardless of how many times the Thread.Suspend() method is called for a given thread, a single call to Thread.Resume() will cause the thread to resume execution.

Destroying Threads If the thread is required to be destroyed, the Thread.Abort() method will allow you to accomplish the task. The runtime aborts the thread by throwing a ThreadAbortException. This exception cannot be caught. If the finally block is present in the method, the runtime will send the control to it. ¤NIIT

Creating Multithreaded Applications 11.9

You can use the following code to destroy threads: using System; using System.Threading; namespace ThreadSample { class BasicThreadApp { public static void ChildThreadCall() { try { Console.WriteLine("Child thread started"); Console.WriteLine ("Child thread - counting to 10"); for (int i = 0; i < 10; i++) { Thread.Sleep(500); Console.Write("{0}...", i); } Console.WriteLine("Child thread finished"); } catch (ThreadAbortException e) { Console.WriteLine("Exception"); } finally { Console.WriteLine ("Child thread -Unable to catch the exception."); } } public static void Main() { ThreadStart ChildRef = new ThreadStart(ChildThreadCall); Console.WriteLine("Main - Creating Child thread"); Thread ChildThread = new Thread(ChildRef); ChildThread.Start(); //Give the Child thread time to start. Console.WriteLine("Main - Sleeping for 2 seconds"); Thread.Sleep(2000);

} }

Console.WriteLine("\nMain - Aborting Child thread"); ChildThread.Abort(); Console.ReadLine();

}

11.10 Creating Multithreaded Applications

¤NIIT

The output of the preceding code is as follows.

Output of the Destroy Thread Program

In the preceding code, the Main() method pauses for two seconds to make sure that the runtime has had time to start the worker thread. When started, the worker thread starts counting to ten, pausing for a second in between each number. When the Main() method resumes execution after its two seconds pause, it aborts the worker thread. Notice, the finally block is executed after the abort.

¤NIIT

Creating Multithreaded Applications 11.11

Implementing Thread Life Cycle The life cycle of a thread starts when an object of the System.Threading.Thread class is created. The life cycle of the thread ends with task execution. There are various states in the life cycle of a thread. These states are: „ The Unstarted state „ The Runnable state „ The Not Runnable state „ The Dead state The following figure shows the various thread states and methods, which can cause the thread to move from one state to another.

Life Cycle of a Thread

The Unstarted State When an instance of the Thread class is created, the thread enters the unstarted state. A new thread is an empty object of the Thread class, and no system resources such as memory are allocated to it. You have to invoke the Start() method to start the thread.

11.12 Creating Multithreaded Applications

¤NIIT

The Runnable State The thread remains in the unstarted state until the program calls the Start() method of the Thread class, which places the thread in the runnable state and immediately returns control to the calling thread. This state is also called as the ready or started state. The newly started thread and any other threads in the program execute concurrently. A single processor cannot execute more than one thread at a time. Therefore, it maintains a thread queue. When a thread is started, a thread is queued up for the processor time and waits for its turn to get executed. As a result, the state of the thread is said to be runnable and not running.

The Not Runnable State A thread is not in the runnable state if it is: „ Sleeping: A thread is put into the sleeping mode by calling the Sleep() method. A sleeping thread enters the runnable state after the specified time of sleep has elapsed. „ Waiting: A thread can be made to wait for some specified condition to be satisfied by calling the Wait() method. The thread can be notified of the condition by invoking the Pulse() method of the Thread class. „ Blocked: A thread could be blocked by an I/O operation.When the thread is blocked, it enters the not runnable state.

The Dead State A running thread enters the dead state when the statements of the threads method are complete. This state is also called the terminated state. A program can force a thread into the dead state by calling the Abort() method of the Thread class on the appropriate thread object. The Abort() method throws a ThreadAbortException in the thread, normally causing the thread to terminate. When a thread is in the dead state and there are no references to the thread object, the garbage collector can remove the thread object from memory.

¤NIIT

Creating Multithreaded Applications 11.13

Activity: Hangman Game Problem Statement The next door children request you to create the Hangman game for them. The game asks a user to enter a category as Book or Movie. Based on the category, a book name or movie name is extracted and the user is asked to guess the name by giving the character and its position in a string. A user will get 60 seconds to play the game. Develop the Hangman game application.

Solution To solve the preceding problem, you need to perform the following tasks: 1. Identify the data source where the name of the book or movie is stored. 2. Create a console-based application for the Hangman game. 3. Build and execute the application. Task 1: Identifying the Data Source Where the Name of the Book or Movie is Stored To demonstrate the implementation of the Hangman game, you need to perform the following steps: 1. Identify the data source. The data source from where data needs to be retrieved is TextTest.txt. 2. Save the TextTest.txt in C drive. Task 2: Creating a Console-Based Application for the Hangman Game To create a console-based application for the Hangman game, you need to perform the following steps: 1. Select StartÆAll ProgramsÆMicrosoft Visual Studio 2005ÆMicrosoft Visual Studio 2005. The Start Page - Microsoft Visual Studio 2005 window is displayed. 2. Select FileÆNewÆProject. The New Project window is displayed. 3. Select the Project type as Visual C# from the Project types pane and Console Application from the Templates pane. 4. Type the name of the new project as HangmanApp in the Name text box. 5. Specify the location where the new project is to be created as c:\chapter11\Activity1 in the Location combo box. 6. Click the OK button. 11.14 Creating Multithreaded Applications

¤NIIT

7.

Open Solution Explorer window and right-click the Program.cs file. The shortcut menu is displayed. 8. Select the Rename option and type the name as Hangman.cs. 9. Double-click the Hangman.cs file in the Solution Explorer window. The code view of Hangman.cs class is displayed. 10. Replace the existing code with the following code: /*Program to play Hangman game. The program asks a user to enter a category as Book/Movie. Based on the category provided, a book name or category name is extracted and the user is asked to guess the name by giving the character and its position.*/ using System; using System.IO; using System.Threading; namespace Game { public class Hangman { string randomString, userString; int dataLength; string Category; string[] bookData = new string[5]; string[] movieData = new string[5]; int bookCount = 0, movieCount = 0; public Hangman() { FillNameValues(); } // Stores the movie names and Book names in respective strings private void FillNameValues() { //Declaring the variables string firstLine; // open the file for reading StreamReader sRead = new StreamReader("c:\\TextTest.txt"); sRead.BaseStream.Seek(0, SeekOrigin.Begin); //Reading the content of the file firstLine = sRead.ReadLine(); while (firstLine != null) { //Storing the Book names in the BookData array if (firstLine.Substring(0, 1) == "B") { int stringStartPos = firstLine.IndexOf(':'); bookData[bookCount] = firstLine.Substring(stringStartPos + 1); bookCount++; ¤NIIT

Creating Multithreaded Applications 11.15

} //Storing the Movie names in the MovieData array else { int stringStartPos = firstLine.IndexOf(':'); movieData[movieCount] = firstLine.Substring(stringStartPos + 1); movieCount++; } firstLine = sRead.ReadLine(); } } public int AcceptCategory() { //Accepting the choice of the user in terms of the Category Console.WriteLine("Enter the Category to Play Book/Movie"); Category = Console.ReadLine(); Category = Category.ToUpper(); if (Category != "BOOK" && Category != "MOVIE") { Console.WriteLine("Invalid Category....\n"); return 0; } else { ExtractName(); return 1; } } public void ExtractName() { //Creating the object of the Random class Random RandGen = new Random(); if (Category == "BOOK") {//Randomly selecting the Book name from the array int Rnd = RandGen.Next(0, bookCount - 1); //Calling the play method randomString = bookData[Rnd]; } else {//Randomly selecting the Movie name from the array int Rnd = RandGen.Next(0, movieCount - 1); //Calling the Startplay method randomString = movieData[Rnd]; } } /*This method will allow the user to give the characters and 11.16 Creating Multithreaded Applications

¤NIIT

displaying his status as to WON or LOST */ public void StartGame() { //Calculating the length of movie/book name dataLength = randomString.Length; //Declaring Variables char locateChar; int correctCnt = 0, inCorrectCnt = 0; int i, k; //Decalring string to store user input char[] s = new char[randomString.Length]; //Loop to accept the characters and its positions //Loop allows user to attempt 2 times more than the total characters InitializeUserString(); ShowUserInputString(); if (Category == "BOOK") { Console.WriteLine("The total number of characters in the Book: {0}", randomString.Length); Console.WriteLine("The total number of characters you can enter to guess the name of Book: {0}", randomString.Length + 2); } else { Console.WriteLine("The total number of characters in the Movie: {0}", randomString.Length); Console.WriteLine("The total number of characters you can enter to guess the name of Movie: {0}", randomString.Length + 2); } for (i = 1, k = 0; i <= dataLength + 2 || k == dataLength; i++) { if (correctCnt == dataLength || inCorrectCnt == dataLength) break; Console.WriteLine("Enter the char "); locateChar = Convert.ToChar(Console.ReadLine().ToLower()); int foundPos = 0; int foundChar = 0; // To extract each character of a string foreach (char c in randomString) { if (c == locateChar) { UpdateString(foundPos, locateChar.ToString()); k++; foundChar = 1; } foundPos++; ¤NIIT

Creating Multithreaded Applications 11.17

} if (foundChar == 0) { Console.WriteLine("Wrong Attempt...Better Luck Next Time!!\n\n"); inCorrectCnt++; } else { correctCnt++; } ShowUserInputString(); Console.WriteLine("Total Correct Attempts: {0}\t", correctCnt); Console.WriteLine("Total Incorrect Attempts: {0}\n", inCorrectCnt); if (k == dataLength) break; } if (randomString==userString) { Console.WriteLine("You have Won \n"); } else { Console.WriteLine("The Correct name is {0}", randomString); Console.WriteLine("You have lost \n"); } } private void UpdateString(int fPos, string updateStr) { string beforeString, afterString; if (fPos != 0 && fPos != dataLength - 1) { if (fPos == 1) beforeString = userString.Substring(0, 1); else beforeString = userString.Substring(0, fPos); afterString = userString.Substring(fPos + 1, dataLength - (fPos + 1)); userString = beforeString + updateStr + afterString; } if (fPos == 0) { afterString = userString.Substring(fPos + 1, dataLength - (fPos + 1)); userString = updateStr + afterString; } if (fPos == dataLength - 1) { beforeString = userString.Substring(0, fPos); 11.18 Creating Multithreaded Applications

¤NIIT

}

}

userString = beforeString + updateStr;

public void InitializeUserString() { userString = " "; for (int i = 0; i < dataLength; i++) { userString = userString.Insert(i, "*"); } } public void ShowUserInputString() { Console.Clear(); Console.WriteLine("Input Value: {0} \n\n", userString); }

}

¤NIIT

} class Game { static void Main(string[] args) { Console.Clear(); Console.WriteLine("You have to complete the game within 60 seconds"); Hangman obj = new Hangman(); int returnVal = obj.AcceptCategory(); if (returnVal == 1) { //obj.StartGame(); Thread t = new Thread(new ThreadStart(obj.StartGame)); t.Start();//Starting the new thread Thread.Sleep(60000);//Making the Main thread sleep for 90 Seconds try { t.Abort(); Console.WriteLine("Time Over"); }//Killing the new thread catch (ThreadAbortException e) { Console.WriteLine(e.Message); } } Console.ReadLine(); } }

Creating Multithreaded Applications 11.19

Task 3: Building and Executing the Application To build and execute the application, perform the following steps: 1. Select BuildÆBuild Solution or press F6 to build the solution. 2. Select DebugÆStart Debugging or press F5 to execute the application. 3. Verify the output of the program executed. The following window verifies the output of the executed program.

Output of the Hangman Game

11.20 Creating Multithreaded Applications

¤NIIT

Implementing Multithreading Multithreading helps to perform various operations simultaneously and saves time of a user. A multithreaded program has a main thread and other user-defined threads to perform multiple tasks simultaneously. The microprocessor allocates memory to the processes that you execute. Each process occupies its own address space or memory. However, all the threads in a process occupy the same address space. Multithreading allows you to achieve multitasking in a program. Multitasking is the ability to execute more than one task at the same time. Multitasking can be divided into the following categories: „ Process-based multitasking: This multitasking feature enables you to switch from one program to another so fast that it appears as if the programs are executing at the same time. For example, process-based multitasking enables you to run the C# compiler and use the text editor at the same time. „ Thread-based multitasking: A single program can contain two or more threads and therefore, perform two or more tasks simultaneously. For example, a text editor can perform writing to a file and print a document simultaneously with separate threads performing the writing and printing actions. In the text-editor, you can format text in a document and print the document at the same time. There are fewer overloads when the processor switches from one thread to another. Therefore, threads are called lightweight processes. On the other hand, when the processor switches from one process to another process the overload increases.

Advantages and Limitations of Multithreading This section lists some of the advantages and limitation of multithreading.

Advantages of Multithreading The advantages of multithreading are: „ Improved performance: Provides improvement in the performance of the processor by simultaneous execution of computation and the I/O operations. „ Minimized system resource usage: Minimizes the use of system resources by using threads, which share the same address space and belong to the same process. „ Simultaneous access to multiple applications: Provides access to multiple applications at the same time because of quick context switching among threads. „ Program structure simplification: Simplifies the structure of complex applications, such as multimedia applications. Each activity can be written in separate methods that makes complex program easy to design and code.

¤NIIT

Creating Multithreaded Applications 11.21

Limitations of Multithreading The limitations of multithreading are: „ Race condition: When two or more threads simultaneously access a variable, at least one thread tries to write a value in the variable. This is called the race condition, which is caused by the lack of synchronization between two threads. For example, in a word processor program, there are two threads, one to read from a file and the other to write to a file. The thread to read a file waits for the thread to write before performing its operation. The race condition arises when the thread to read a file, reads the file, before the thread to write to a file performs its operation. „ Deadlock condition: This condition arises in a computer system when two threads wait for each other to complete their operations before performing their individual action. As a result, the two threads become locked and the program fails. For example, there are two threads, ThreadA and ThreadB. ThreadA is waiting for a lock to be released by ThreadB, and ThreadB is waiting for the lock to be released by ThreadA to complete its transaction. This state is a deadlock. „ Lock starvation: This limitation arises when the execution of a thread is postponed because of its low priority. The .NET runtime environment executes threads based on their priority because the processor can execute only one thread at a time.The thread with a higher priority is executed before the thread with a lower priority.

Creating Multiple Threads You can create multiple threads in a program by extending the Thread class. You can use the following code to create two child threads other than the main thread: using System; using System.Threading; class ThreadSchedule { public static void ChildThread1() { Console.WriteLine("Child thread 1 started"); Console.WriteLine("Child thread - counting from 1 to 10"); for (int T = 1; T < 11; T++) { for (int Cnt = 0; Cnt < 100; Cnt++) { Console.Write("."); // Code to imitate work being done. } Console.Write("{0}", T); } Console.WriteLine("Child thread 1 finished"); 11.22 Creating Multithreaded Applications

¤NIIT

} public static void ChildThread2() { Console.WriteLine("Child thread

2 started");

Console.WriteLine("Child thread - counting slowly from 11 to 20"); for (int T = 11; T < 20; T++) { for (int Cnt = 0; Cnt < 100; Cnt++) { Console.Write("."); // Code to imitate work being done. } Console.Write("{0}", T); } }

Console.WriteLine("Child thread 2 finished");

public static void Main() { ThreadStart Child1 = new ThreadStart(ChildThread1); ThreadStart Child2= new ThreadStart(ChildThread2); Console.WriteLine("Main - Creating Child threads"); Thread Thread1 = new Thread(Child1); Thread Thread2 = new Thread(Child2); Thread1.Start(); Thread2.Start(); }

¤NIIT

}

Creating Multithreaded Applications 11.23

Identifying the Thread Priority One of the attributes that controls the behavior of a thread is its priority. The .NET Run-time Environment executes threads based on their priority. Only one thread is executed by the CPU at a time. Therefore, the threads, which are at the runnable state for execution, queue up for their turn to get executed by the processor. The threads are fixedpriority scheduled. Each thread with its priority has its position in the thread queue of the processor.

Defining Thread Priority Thread priority is the property that specifies the priority of one thread with respect to the priority of another thread. Execution of multiple threads is scheduled on a single processor in a specified order. Thread priority can be defined as: „ Above normal „ Below normal „ Highest „ Lowest „ Normal A thread with higher priority runs before threads, which have lower priority. If C# encounters another thread with higher priority, the current thread is pushed back; and the thread with the higher priority is executed. The .NET runtime system selects the runnable thread with the highest priority of execution when a number of threads get ready to execute. The next thread of lower priority starts executing if the higher priority thread stops or becomes not runnable. A thread is pushed back in the queue by another thread if it is waiting for an I/O operation. A thread can also be pushed back in the queue when the time for which the Sleep() method was called on another higher priority thread is over.

Setting the Thread Priority You can set the thread priority after it is created using the Priority property of the The following syntax shows how to set the thread priority:

Thread class.

NewThread.Priority = ThreadPriority.Highest;

In the preceding syntax, the ThreadPriority.Highest property specifies the new priority setting for a thread. Threads are scheduled for execution based on their priority. Even though threads are executing within run time, all threads are assigned processor time 11.24 Creating Multithreaded Applications

¤NIIT

slices by the operating system. The details of the scheduling algorithm used to determine the order in which threads are executed varies with each operating system. If multiple threads with the same priority are available, the scheduler cycles through the threads in that priority, giving each thread a fixed time slice in which to execute. As long as a thread with a higher priority is available to run, lower priority threads do not get to execute. When there are no more runnable threads at a given priority, the scheduler moves to the next lower priority and schedules the threads at that priority for execution. You can use the following code, to set the priority of the child threads: using System; using System.Threading; class ThreadSchedule { public static void ChildThread1() { Console.WriteLine("Child thread 1 started"); Console.WriteLine("Child thread - counting from 1 to 10"); for (int T = 1; T < 11; T++) { for (int Cnt = 0; Cnt < 100; Cnt++) { Console.Write("."); // Code to imitate work being done. } Console.Write("{0}", T); } }

Console.WriteLine("Child thread 1 finished");

public static void ChildThread2() { Console.WriteLine("Child thread 2 started"); Console.WriteLine("Child thread - counting from 11 to 20"); for (int T = 11; T < 20; T++) { for (int Cnt = 0; Cnt < 100; Cnt++) { Console.Write("."); // Code to imitate work being done. } Console.Write("{0}", T); } }

Console.WriteLine("Child thread 2 finished");

public static void Main() ¤NIIT

Creating Multithreaded Applications 11.25

{

ThreadStart Child1 = new ThreadStart(ChildThread1); ThreadStart Child2 = new ThreadStart(ChildThread2); Console.WriteLine("Main - Creating Child threads"); Thread Thread1 = new Thread(Child1); Thread Thread2 = new Thread(Child2); Thread1.Priority = ThreadPriority.Highest; Thread2.Priority = ThreadPriority.Lowest; Thread1.Start(); Thread2.Start();

}

}

When a processor is informed about the priority of a thread, the operating system eventually uses the information as a part of its scheduling algorithm. The processor then relays that information. In .NET, this algorithm is based on the priority level used with the Thread.Priority property, as well as the process’s priority class in the preceding code.

11.26 Creating Multithreaded Applications

¤NIIT

Using Synchronization in Threads In a multithreaded application, when threads need to share data with each other, the application should ensure that one thread does not change the data used by the other thread. For example, if you have two threads, one that reads your salary from a file and another thread that tries to update the salary, data corruption might occur. C# enables you to coordinate the actions of multiple threads by using synchronized methods or synchronized statements.

Synchronizing Threads Synchronization of threads ensures that if two or more threads need to access a shared resource then that resource is used by only one thread at a time. You can synchronize your code using the synchronized keyword. You can invoke only one synchronized method for an object at any given time. Synchronization is based on the concept of monitoring. A monitor is an object that is used as a lock to the data members and methods of a class. All objects and classes are associated with the monitor and only one thread can own the monitor at a given time. To enter an object’s monitor, you need to call a method that has been modified with the synchronized keyword. The monitor controls the way in which synchronized methods access an object or a class. When a thread acquires a lock, it is said to have entered the monitor. The monitor ensures that only one thread has access to the resources at any given time. When a thread is within a synchronized method, all the other threads that try to call it on the same instance have to wait. During the execution of a synchronized method, the object is locked so that no other synchronized method can be invoked. The monitor is automatically released when the method completes its execution. The monitor can also be released when the synchronized method executes the Wait() method. When a thread calls the Wait() method, it temporarily releases the locks that it holds. In addition, the thread stops running and is added to the list of waiting threads for that object.

¤NIIT

Creating Multithreaded Applications 11.27

The following figure shows how synchronization is maintained among threads.

Thread Synchronization

Locking Code Using the Monitor Locks The System.Monitor class enables you to serialize the access to blocks of code by means of locks and signals. For example, you have a method that writes content to a file and the method cannot be executed by two or more threads at the same time. If the work being performed by this method is especially time-consuming and you have multiple threads, any of which might call this method, you could have a serious problem on your hands. This is where the Monitor class proves useful. Consider an example on synchronization. You have two threads, both of which will call the WriteData() method. To incorporate the Monitor class in this example, you can use two of its static methods. The first method is called Enter. When executed, this method attempts to obtain a monitor lock on the object. If another thread already has the lock, the method will block until that lock has been released. The Monitor.Exit() method is then called to release the lock. 11.28 Creating Multithreaded Applications

¤NIIT

The following example forces the serialization of access to the WriteData() method: using System; using System.Threading; namespace ThreadExample { class FileAccess { public void WriteData(string Data) { Monitor.Enter(this); Console.WriteLine("FileAccess.WriteData - Started"); Console.WriteLine("FileAccess.WriteData - Working"); for (int Cnt = 0; Cnt < 100; Cnt++) { Console.Write(Data); } Console.WriteLine("FileAccess.WriteData - Ended");

}

}

Monitor.Exit(this);

class ThreadMonitorClass { public static FileAccess Fd = new FileAccess(); public static void ChildThread1() { Console.WriteLine("Child thread #1 - Started"); Console.WriteLine("Child thread #1-Calling FileAccess.WriteData"); Fd.WriteData("T1");

}

Console.WriteLine("Child thread #1 - Returned from Output");

public static void ChildThread2() { Console.WriteLine("Child thread #2 - Started"); Console.WriteLine ("Child thread #2 - Calling FileAccess.WriteData"); Fd.WriteData("T2"); Console.WriteLine("Child thread #2 - Returned from Output"); } public static void Main() ¤NIIT

Creating Multithreaded Applications 11.29

{

ThreadStart Child1 = new ThreadStart(ChildThread1); ThreadStart Child2 = new ThreadStart(ChildThread2); Console.WriteLine("Main - Creating Child threads"); Thread Thread1 = new Thread(Child1); Thread Thread2 = new Thread(Child2);

}

}

Thread1.Start(); Thread2.Start(); Console.ReadLine();

}

The output of the preceding code is as follows.

Output of the Thread Synchronization Program

Using Monitor Locks with the C# Lock Statement The other way to lock code is by using the C# lock statement. Although the C# lock statement does not support the full array of features found in the Monitor class, it enables you to obtain and release a monitor lock. To use the lock statement, simply specify the lock statement with the code being serialized in braces. The braces indicate the starting and stopping point of code being protected. Therefore, there is no need for an unlock statement. 11.30 Creating Multithreaded Applications

¤NIIT

The following code will produce a synchronized output that is similar to the output of the preceding code: using System; using System.Threading; namespace ThreadExample { class FileAccess { public void WriteData(string Data) { lock (this) { Console.WriteLine("FileAccess.WriteData - Started"); Console.WriteLine("FileAccess.WriteData - Working"); for (int Cnt = 0; Cnt < 100; Cnt++) { Console.Write(Data); } } }

Console.WriteLine("FileAccess.WriteData - Ended");

}

class ThreadLockClass { public static FileAccess Fd = new FileAccess(); public static void ChildThread1() { Console.WriteLine("Child thread #1 - Started"); Console.WriteLine ("Child thread #1 - Calling FileAccess.WriteData "); Fd.WriteData("T1");

}

Console.WriteLine("Child thread #1 - Returned from Output");

public static void ChildThread2() { Console.WriteLine("Child thread #2 - Started"); Console.WriteLine ("Child thread #2 - Calling FileAccess.WriteData "); Fd.WriteData("T2");

} ¤NIIT

Console.WriteLine("Child thread #2 - Returned from Output");

Creating Multithreaded Applications 11.31

public static void Main() { ThreadStart Child1 = new ThreadStart(ChildThread1); ThreadStart Child2 = new ThreadStart(ChildThread2); Console.WriteLine("Main - Creating Child threads"); Thread Thread1 = new Thread(Child1); Thread Thread2 = new Thread(Child2);

} }

Thread1.Start(); Thread2.Start(); Console.ReadLine();

}

The output of the preceding code is as follows.

Output of the Thread Synchronization Program Using the Lock Statement

11.32 Creating Multithreaded Applications

¤NIIT

Identifying Communication Between Processes A process is a running instance of a program. The communication between the processes at run time within the same computer or over a network is called the interprocess communication. To allow the interprocess communication, special techniques and mechanisms are used. Consider an example. Imagine you are typing a document. You use your fingers to type? Your brain works while you are typing the document. Your brain directs one of your fingers to hit a key while the other finger hits another key. Your brain synchronizes typing with both your hands. It directs you to type the letters of a word that come to your mind. The working of your brain is an example of interprocess communication within human body. Based on this example, you can conclude that a medium is required for communication between various processes. Similarly, computer programs need some mechanism for communication. Processes can use the available memory of the system to communicate with each other, but memory is completely managed by the operating system. A process will be allotted some part of the available memory for execution by the operating system. Each process will execute in its own unique user space. The operating system will not allow the memory allotted for one process to overlap with the memory allotted for another process. To allow communication between various processes with a unique address space, the operating system's kernel acts as the communication channel.

Application Domain Whenever you start an application in OS such as Windows XP, the system starts a Win32 process and executes your application. These processes use resource such as memory, objects, and kernel. Each Win32 process contains at the least one thread. If you were to run other tasks or open up other applications through your application, those tasks will belong to the Win32 process running on a collection of multiple threads. So when an application is run, a new application domain is created. Several instantiations of an application can exist on the same machine at a given time, and each has its own application domain. An application domain enables application isolation by acting as a container for application state. In .NET, threads execute in an application domain. A thread in one process cannot invoke a method in a thread that belongs to another process. In .NET, however, threads can cross the application domain boundaries, and a method in one thread can call a method in another application domain. The application domain is a logical process inside a physical process. ¤NIIT

Creating Multithreaded Applications 11.33

The execution of a process and running your code within it is usually the domain and choice of the operating system. There are many complex situations and issues that the operating system has to handle while maintaining an active process. The following figure shows various application domains interacting with each other.

The Application Domain

The main purpose of the application domain is to isolate your applications from the other applications. Application domains run on a single process. Therefore, you run an application within an application domain and you run multiple application domains within a single process. With the .NET CLR's ability to run a managed code, you can further prevent memory leaks and crashes. Objects in the same application domain communicate directly, while objects that exist in different application domains interact with each other by transporting copies of the objects to each other. You use the System.AppDomain class to manage application domains. The AppDomain class implements a set of events that enable applications to respond when an assembly is loaded, when an application domain will be unloaded, or when an unhandled exception is thrown.

11.34 Creating Multithreaded Applications

¤NIIT

Practice Questions 1.

Which of the following is true about the 'not runnable' state of a thread? a. A sleeping thread enters the 'not runnable' state when the specified time has elapsed. b. A thread is in a ‘not runnable’ state if it is dead. c. When the Start() method is invoked, the thread enters the ‘not runnable’ state. d. When a thread is blocked by another thread, it enters the 'not runnable' state.

2.

You need to create a spreadsheet application with automatic recalculation facility. Which of the following statements is/are true with respect to the required application? A. The application should be multithreaded. B. A thread object has to be created for performing automatic recalculation. C. The thread taking care of automatic recalculation should have the highest priority. a. A only b. A, B, & C c. B & C d. A & B

3.

Which class is used to construct and access individual threads in a multithreaded application? a. b. c. d.

System.Thread System.Threading System.Thread.Threading System.Threading.Thread

4.

You are creating an application, using the concept of multithreading, in which you can play audio files and watch animated images at the same time. Which of the following methods should be invoked for a thread to enter the runnable state? a. start() b. sleep() c. Run() d. Resume()

5.

You are developing a multithreaded application. Which of the following will you use to make a thread, animThread, enter the non-runnable state? a. Thread animThread=new Thread(this); b. animThread.Sleep(2000); c. animThread.Resume(); d. animThread.Start();

¤NIIT

Creating Multithreaded Applications 11.35

Summary In this chapter, you learned that: „ A thread is defined as the path of execution of a program. It is a sequence of instructions that is executed to define a unique flow of control. „ A program that creates two or more threads is called a multithreaded program. „ The types of multitasking are: z Process-based multitasking z Thread-based multitasking „ The advantages of multithreading are: z Improved performance z Minimized system resources usage z Simultaneous access to multiple applications „ The various disadvantages of multithreading are: z Race condition z Deadlock condition z Lock starvation „ The System.Threading class is used to construct and access individual threads in a multithreaded application. „ The various states in the life cycle of a thread are: z UnStarted state z Runnable state z Not Runnable state z Dead state „ Thread priority is the property that specifies the priority of one thread with respect to the priority of another thread. „ Synchronization of threads ensures that if two or more threads need to access a shared resource then that resource is used by only one thread at a time. „ The System.Monitor class enables you to serialize the access to blocks of code by means of locks and signals. „ The communication between processes at runtime within the same computer or over a network is called inter-process communication. „ The application domain is a logical process inside a physical process. The main purpose of the application domain is to isolate your applications from the other applications.

11.36 Creating Multithreaded Applications

¤NIIT

Exercises Exercise 1 Write an application to simulate the vehicles crossing a toll bridge on a motorway. For the purpose of this exercise, simulate the environment for five vehicles that are approaching the bridge and the toll booth. The vehicles are numbered from one to five. The vehicles should approach the bridge and the toll booth in sequential order. The toll booth can only deal with one vehicle at a time. The simulation is performed by having one thread for each vehicle, and consists of three classes: „ Vehicle: Simulate the behavior of a vehicle „ TollBooth: Simulate the behavior of a toll booth „ Simulate: Creates the vehicles and controls the simulation

¤NIIT

Creating Multithreaded Applications 11.37

11.38 Creating Multithreaded Applications

¤NIIT

Creating Multithreaded Applications -

process that creates two or more threads is called a multithreaded process. ... In C#, you create a thread by creating an object of type Thread, giving its ...

923KB Sizes 2 Downloads 270 Views

Recommend Documents

Oracle12c multithreaded Oracle Database model.pdf
Oracle12c multithreaded Oracle Database model.pdf. Oracle12c multithreaded Oracle Database model.pdf. Open. Extract. Open with. Sign In. Main menu.

Oracle12c multithreaded Oracle Database model.pdf
There was a problem previewing this document. Retrying... Download. Connect more apps... Try one of the apps below to open or edit this item. Main menu.

Creating Multi-Tier Web Applications with PHP
3. Web- server. Multi-Tier Architecture (1). Smarty. Browser. PHP. Sessions. RDBMS .NET. COM ... Data is available for other applications (e.g. monthly turnover ...

Creating affordable Internet map server applications ...
These tools include merging DEM data together, clipping data sets to the watershed boundary, and watershed modeling tools to compute the upstream ...